{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T03:33:35.633807900Z",
     "start_time": "2024-05-02T03:33:24.637409400Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=9, micro=7, releaselevel='final', serial=0)\n",
      "matplotlib 3.8.4\n",
      "numpy 1.26.4\n",
      "pandas 2.2.2\n",
      "sklearn 1.4.2\n",
      "torch 2.2.2+cpu\n",
      "cpu\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n",
    "torch.manual_seed(seed)\n",
    "torch.cuda.manual_seed_all(seed)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据准备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T03:33:53.350580400Z",
     "start_time": "2024-05-02T03:33:52.447226500Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "--2024-05-02 11:33:52--  https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt\n",
      "Resolving storage.googleapis.com (storage.googleapis.com)... 142.251.42.251, 172.217.163.59, 142.251.43.27\n",
      "Connecting to storage.googleapis.com (storage.googleapis.com)|142.251.42.251|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 1115394 (1.1M) [text/plain]\n",
      "Saving to: 'shakespeare.txt.1'\n",
      "\n",
      "     0K .......... .......... .......... .......... ..........  4% 1.11M 1s\n",
      "    50K .......... .......... .......... .......... ..........  9% 2.06M 1s\n",
      "   100K .......... .......... .......... .......... .......... 13% 3.26M 1s\n",
      "   150K .......... .......... .......... .......... .......... 18% 5.05M 0s\n",
      "   200K .......... .......... .......... .......... .......... 22% 5.38M 0s\n",
      "   250K .......... .......... .......... .......... .......... 27% 7.16M 0s\n",
      "   300K .......... .......... .......... .......... .......... 32% 8.86M 0s\n",
      "   350K .......... .......... .......... .......... .......... 36% 10.4M 0s\n",
      "   400K .......... .......... .......... .......... .......... 41% 10.4M 0s\n",
      "   450K .......... .......... .......... .......... .......... 45% 10.2M 0s\n",
      "   500K .......... .......... .......... .......... .......... 50% 9.23M 0s\n",
      "   550K .......... .......... .......... .......... .......... 55% 5.95M 0s\n",
      "   600K .......... .......... .......... .......... .......... 59% 20.3M 0s\n",
      "   650K .......... .......... .......... .......... .......... 64% 11.1M 0s\n",
      "   700K .......... .......... .......... .......... .......... 68% 10.2M 0s\n",
      "   750K .......... .......... .......... .......... .......... 73% 9.33M 0s\n",
      "   800K .......... .......... .......... .......... .......... 78% 5.51M 0s\n",
      "   850K .......... .......... .......... .......... .......... 82% 31.2M 0s\n",
      "   900K .......... .......... .......... .......... .......... 87% 28.6M 0s\n",
      "   950K .......... .......... .......... .......... .......... 91% 32.4M 0s\n",
      "  1000K .......... .......... .......... .......... .......... 96% 21.2M 0s\n",
      "  1050K .......... .......... .......... .........            100% 37.1M=0.2s\n",
      "\n",
      "2024-05-02 11:33:53 (6.07 MB/s) - 'shakespeare.txt.1' saved [1115394/1115394]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "!wget https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T03:34:17.403227100Z",
     "start_time": "2024-05-02T03:34:17.340262900Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "length 1115394\n",
      "First Citizen:\n",
      "Before we proceed any further, hear me speak.\n",
      "\n",
      "All:\n",
      "Speak, speak.\n",
      "\n",
      "First Citizen:\n",
      "You\n"
     ]
    }
   ],
   "source": [
    "# https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt\n",
    "#文件已经下载好了\n",
    "with open(\"./shakespeare.txt\", \"r\", encoding=\"utf8\") as file:\n",
    "    text = file.read()\n",
    "\n",
    "print(\"length\", len(text))\n",
    "print(text[0:100])"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 构造字典"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T03:35:03.291567900Z",
     "start_time": "2024-05-02T03:35:03.256958Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "65\n",
      "['\\n', ' ', '!', '$', '&', \"'\", ',', '-', '.', '3', ':', ';', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']\n"
     ]
    }
   ],
   "source": [
    "# 1. generate vocab\n",
    "# 2. build mapping char->id\n",
    "# 3. data -> id_data  把数据都转为id\n",
    "# 4. a b c d [EOS] -> [BOS] b c d  预测下一个字符生成的模型，也就是输入是a，输出就是b\n",
    "\n",
    "#去重，留下独立字符，并排序\n",
    "vocab = sorted(set(text))\n",
    "print(len(vocab))\n",
    "print(vocab)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T03:35:20.085213700Z",
     "start_time": "2024-05-02T03:35:20.065221300Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 how\n",
      "1 are\n",
      "2 you\n"
     ]
    }
   ],
   "source": [
    "for idx,char in enumerate(['how','are','you']):\n",
    "    print(idx,char)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T03:35:59.556256500Z",
     "start_time": "2024-05-02T03:35:59.535220300Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'\\n': 0, ' ': 1, '!': 2, '$': 3, '&': 4, \"'\": 5, ',': 6, '-': 7, '.': 8, '3': 9, ':': 10, ';': 11, '?': 12, 'A': 13, 'B': 14, 'C': 15, 'D': 16, 'E': 17, 'F': 18, 'G': 19, 'H': 20, 'I': 21, 'J': 22, 'K': 23, 'L': 24, 'M': 25, 'N': 26, 'O': 27, 'P': 28, 'Q': 29, 'R': 30, 'S': 31, 'T': 32, 'U': 33, 'V': 34, 'W': 35, 'X': 36, 'Y': 37, 'Z': 38, 'a': 39, 'b': 40, 'c': 41, 'd': 42, 'e': 43, 'f': 44, 'g': 45, 'h': 46, 'i': 47, 'j': 48, 'k': 49, 'l': 50, 'm': 51, 'n': 52, 'o': 53, 'p': 54, 'q': 55, 'r': 56, 's': 57, 't': 58, 'u': 59, 'v': 60, 'w': 61, 'x': 62, 'y': 63, 'z': 64}\n"
     ]
    }
   ],
   "source": [
    "#每个字符都编好号，enumerate对每一个位置编号，生成的是列表中是元组，下面字典生成式\n",
    "char2idx = {char:idx for idx, char in enumerate(vocab)}\n",
    "print(char2idx)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T03:36:09.961945600Z",
     "start_time": "2024-05-02T03:36:09.937954400Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['\\n' ' ' '!' '$' '&' \"'\" ',' '-' '.' '3' ':' ';' '?' 'A' 'B' 'C' 'D' 'E'\n",
      " 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W'\n",
      " 'X' 'Y' 'Z' 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o'\n",
      " 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z']\n"
     ]
    }
   ],
   "source": [
    "# 把vocab从列表变为ndarray\n",
    "idx2char = np.array(vocab)\n",
    "print(idx2char)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T06:41:44.749942100Z",
     "start_time": "2024-05-02T06:41:44.553033100Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(1115394,)\n",
      "1115394\n",
      "[18 47 56 57 58  1 15 47 58 47]\n",
      "First Citi\n"
     ]
    }
   ],
   "source": [
    "#把字符都转换为id\n",
    "text_as_int = np.array([char2idx[c] for c in text])\n",
    "print(text_as_int.shape)\n",
    "print(len(text_as_int))\n",
    "print(text_as_int[0:10])\n",
    "print(text[0:10])"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 把莎士比亚文集分成一个一个的样本"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T06:42:32.623905300Z",
     "start_time": "2024-05-02T06:42:32.605911400Z"
    }
   },
   "outputs": [],
   "source": [
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "class CharDataset(Dataset):\n",
    "    #text_as_int是字符的id列表，seq_length是每个样本的长度\n",
    "    def __init__(self, text_as_int, seq_length):\n",
    "        self.sub_len = seq_length + 1 #一个样本的长度\n",
    "        self.text_as_int = text_as_int\n",
    "        self.num_seq = len(text_as_int) // self.sub_len #样本的个数\n",
    "        \n",
    "    def __getitem__(self, index):#index是样本的索引，返回的是一个样本，比如第一个，就是0-100的字符\n",
    "        return self.text_as_int[index * self.sub_len: (index + 1) * self.sub_len]\n",
    "    \n",
    "    def __len__(self): #返回样本的个数\n",
    "        return self.num_seq\n",
    "\n",
    "#batch是一个列表，列表中的每一个元素是一个样本，有101个字符，前100个是输入，后100个是输出\n",
    "def collat_fct(batch):\n",
    "    src_list = []\n",
    "    trg_list = []\n",
    "    for part in batch:\n",
    "        src_list.append(part[:-1]) #输入\n",
    "        trg_list.append(part[1:]) #输出\n",
    "        \n",
    "    src_list = np.array(src_list) #把列表转换为ndarray\n",
    "    trg_list = np.array(trg_list) #把列表转换为ndarray\n",
    "    return torch.Tensor(src_list).to(dtype=torch.int64), torch.Tensor(trg_list).to(dtype=torch.int64) #返回的是一个元组，元组中的每一个元素是一个torch.Tensor\n",
    "        \n",
    "\n",
    "train_ds = CharDataset(text_as_int, 100)\n",
    "train_dl = DataLoader(train_ds, batch_size=64, shuffle=True, collate_fn=collat_fct)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-05-02T06:55:10.459329600Z",
     "start_time": "2024-05-02T06:55:10.332402300Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[41, 13, 56, 55,  0, 45, 64, 48, 11, 48, 57, 31, 57, 16, 10,  7,  1,  0,\n",
      "         45, 34, 13, 20, 36, 23, 56, 11, 10, 58, 52, 40, 45,  7, 22, 11, 47, 22,\n",
      "          8, 22, 20, 30, 47, 14,  8, 22, 52, 17, 40, 55, 53, 16, 30, 22, 20, 22,\n",
      "         51, 55, 50, 35, 30,  6, 38, 21, 17,  8, 23,  0,  7,  3,  8, 49, 28,  1,\n",
      "         33, 24, 26, 48, 61, 41, 20, 53, 38, 30, 58, 29, 38, 24, 48, 37, 15, 13,\n",
      "         53, 55, 35, 12, 25, 17, 35, 17, 62, 56]])\n",
      "=================================== 一层单向 RNN ===================================\n",
      "            embedding.weight            paramerters num: 16640\n",
      "            rnn.weight_ih_l0            paramerters num: 262144\n",
      "            rnn.weight_hh_l0            paramerters num: 1048576\n",
      "             rnn.bias_ih_l0             paramerters num: 1024\n",
      "             rnn.bias_hh_l0             paramerters num: 1024\n",
      "               fc.weight                paramerters num: 66560\n",
      "                fc.bias                 paramerters num: 65\n",
      "================================================================================\n"
     ]
    },
    {
     "data": {
      "text/plain": "torch.Size([1, 100, 65])"
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "class CharRNN(nn.Module):\n",
    "    def __init__(self, vocab_size, embedding_dim=256, hidden_dim=1024):\n",
    "        super(CharRNN, self).__init__()\n",
    "        self.embedding = nn.Embedding(vocab_size, embedding_dim)\n",
    "        #batch_first=True,输入的数据格式是(batch_size, seq_len, embedding_dim)\n",
    "        self.rnn = nn.RNN(embedding_dim, hidden_dim, batch_first=True)\n",
    "        self.fc = nn.Linear(hidden_dim, vocab_size)\n",
    "        \n",
    "    def forward(self, x, hidden=None):\n",
    "        x = self.embedding(x)\n",
    "        output, hidden = self.rnn(x, hidden) #这里和02的差异是没有只拿最后一个输出，而是把所有的输出都拿出来了\n",
    "        x = self.fc(output) #[bs, seq_len, hidden_dim]\n",
    "        return x, hidden #x的shape是(batch_size, seq_len, vocab_size)\n",
    "    \n",
    "    \n",
    "vocab_size = len(vocab)\n",
    "sample_inputs = torch.randint(0, vocab_size, (1, 100))\n",
    "print(sample_inputs)\n",
    "print(\"{:=^80}\".format(\" 一层单向 RNN \"))       \n",
    "for key, value in CharRNN(vocab_size).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")\n",
    "print(\"{:=^80}\".format(\"\"))\n",
    "CharRNN(vocab_size)(sample_inputs)[0].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "outputs": [
    {
     "data": {
      "text/plain": "66560"
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "256*1024\n",
    "1024*1024\n",
    "1024*65"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T06:56:39.694430500Z",
     "start_time": "2024-05-02T06:56:39.673444800Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [],
   "source": [
    "my_tensor = torch.randint(0, vocab_size, (64, 100))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T07:22:12.958113600Z",
     "start_time": "2024-05-02T07:22:12.942121400Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "outputs": [
    {
     "data": {
      "text/plain": "torch.Size([6400])"
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_tensor.reshape(-1).shape"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T07:22:19.891355200Z",
     "start_time": "2024-05-02T07:22:19.863772300Z"
    }
   }
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f2021c77ede54f62ab315f88d65395ed",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/17300 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    save_ckpt_callback=None,\n",
    "    stateful=False      # 想用stateful，batch里的数据就必须连续，不能打乱\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    hidden = None\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits, hidden = model(datas, hidden=hidden if stateful else None)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits.reshape(-1, vocab_size), labels.reshape(-1))\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    " \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"step\": global_step\n",
    "                })\n",
    "   \n",
    "                # 保存模型权重 save model checkpoint\n",
    "                if save_ckpt_callback is not None:\n",
    "                    save_ckpt_callback(global_step, model.state_dict(), metric=-loss)\n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 100\n",
    "\n",
    "model = CharRNN(vocab_size=vocab_size)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失 \n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "\n",
    "# save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/text_generation\", save_step=1000, save_best_only=True)\n",
    "\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAikAAAGdCAYAAADXIOPgAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/P9b71AAAACXBIWXMAAA9hAAAPYQGoP6dpAABYo0lEQVR4nO3deVzUdf4H8Nd3hmE4h1PuQxQUVFDBCy2PvLPSrbXWarXLrU23Wtty3W1Lczfdbn8ddljaZZaW1qZpqOGRN4LihaIIiBwCwnAzzHx+f8wBI4dyKF+c1/Px8DHyne935jNvv8KLz/fz+XwlIYQAERERkcwoOrsBRERERE1hSCEiIiJZYkghIiIiWWJIISIiIlliSCEiIiJZYkghIiIiWWJIISIiIlliSCEiIiJZsuvsBlwLg8GAixcvwtXVFZIkdXZziIiI6BoIIVBWVoaAgAAoFK3vF+kSIeXixYsIDg7u7GYQERFRG2RnZyMoKKjVx3WJkOLq6grA+CE1Gk2Hva5Op8Mvv/yCCRMmQKVSddjrdjWsA2sAsAZmrANrALAGZu2tg1arRXBwsOXneGt1iZBivsSj0Wg6PKQ4OTlBo9HY/Elo63VgDVgDM9aBNQBYA7OOqkNbh2pw4CwRERHJEkMKERERyRJDChEREckSQwoRERHJEkMKERERyRJDChEREckSQwoRERHJEkMKERERyRJDChEREckSQwoRERHJEkMKERERyRJDChEREcmSTYeUlXsy8V2GAml5ZZ3dFCIiIrqCTYeUTcfysDNPgezLVZ3dFCIiIrqCTYcU842jDUJ0ajuIiIioMZsOKQrJGFOYUYiIiOTHpkOKKaOwJ4WIiEiGbDyksCeFiIhIrmw6pChMPSnMKERERPJj0yGFA2eJiIjky6ZDCgfOEhERyZdNhxRzV4pgSiEiIpIdmw4plp6UTm4HERERNWbTIYVjUoiIiOTLpkMKx6QQERHJl02HlPrF3Dq3HURERNQYQwo4cJaIiEiO2hVSli5dCkmS8Mwzz7S439q1axEZGQkHBwdER0dj06ZN7XnbDsOBs0RERPLV5pBy8OBBfPjhh4iJiWlxvz179mDGjBl49NFHkZycjGnTpmHatGk4duxYW9+6w3DgLBERkXy1KaSUl5fjgQcewMcffwwPD48W9122bBkmTZqE5557DlFRUVi8eDFiY2Px7rvvtqnBHYn37iEiIpIvu7YcNGfOHEyZMgXjxo3Dv//97xb33bt3L+bNm2e1beLEidiwYUOzx9TU1KCmpsbytVarBQDodDrodLq2NLlppnRSV6fv2NftYsyfnTVgDRo+2irWgTUAWAOz9tahvfVrdUhZs2YNDh8+jIMHD17T/nl5efD19bXa5uvri7y8vGaPWbJkCRYtWtRo+y+//AInJ6fWNbgFlwoUABQ4eeokNpWc6LDX7aoSEhI6uwmdjjVgDcxYB9YAYA3M2lqHysrKdr1vq0JKdnY2nn76aSQkJMDBwaFdb9ySBQsWWPW+aLVaBAcHY8KECdBoNB32PptKk4HiS+jVOxK3jwjrsNftanQ6HRISEjB+/HioVKrObk6nYA1YAzPWgTUAWAOz9tbBfCWkrVoVUpKSklBQUIDY2FjLNr1ej507d+Ldd99FTU0NlEql1TF+fn7Iz8+32pafnw8/P79m30etVkOtVjfarlKpOvRksVMY26pQKGz6JDTr6Pp2RawBa2DGOrAGAGtg1tY6tLd2rRo4O3bsWKSmpiIlJcXyZ9CgQXjggQeQkpLSKKAAQHx8PLZt22a1LSEhAfHx8e1qeEfgYm5ERETy1aqeFFdXV/Tr189qm7OzM7y8vCzbZ86cicDAQCxZsgQA8PTTT2PUqFF44403MGXKFKxZswaHDh3CRx991EEfoe24mBsREZF8dfiKs1lZWcjNzbV8PXz4cKxevRofffQR+vfvj3Xr1mHDhg2Nwk5n4GJuRERE8tWmKcgNJSYmtvg1AEyfPh3Tp09v71t1OC7mRkREJF+2fe8eBRdzIyIikivbDimmR4YUIiIi+bHpkGIZk8KUQkREJDs2HVI4BZmIiEi+bDqkKMxTkDu3GURERNQEmw4p5lEpnN1DREQkPzYdUhRczI2IiEi2bDykcAoyERGRXNl0SOHAWSIiIvmy8ZBiXhafKYWIiEhubDukmB55uYeIiEh+bDqk1A+c7dx2EBERUWM2HVLMl3s4BZmIiEh+bDqkcDE3IiIi+bLpkGLGdVKIiIjkx6ZDCtdJISIiki+GFHBMChERkRzZdEjhYm5ERETyxZACDpwlIiKSI9sOKTCPSWFMISIikhubDilczI2IiEi+bDqk1I9JYUohIiKSGxsPKeYbDBIREZHc2HZIMT1yTAoREZH82HRI4WJuRERE8mXjIcX4yHVSiIiI5MemQwrvgkxERCRfNh5SjI+MKERERPLDkAJA8HoPERGR7Nh0SFFwCjIREZFs2XRIMU9B5pgUIiIi+bHtkMIpyERERLJl4yHF+MiQQkREJD82HVLqx6QwpRAREcmNTYeU+jEpndoMIiIiaoJNhxQF74JMREQkWzYdUjhwloiISL5sPKQYH3kXZCIiIvmx6ZDCxdyIiIjky6ZDChdzIyIikq9WhZTly5cjJiYGGo0GGo0G8fHx+Pnnn5vdf9WqVZAkyeqPg4NDuxvdUTgmhYiISL7sWrNzUFAQli5dioiICAgh8Nlnn2Hq1KlITk5G3759mzxGo9EgLS3N8rU5GMgBF3MjIiKSr1aFlDvvvNPq6//85z9Yvnw59u3b12xIkSQJfn5+bW/hdWSegszF3IiIiOSnVSGlIb1ej7Vr16KiogLx8fHN7ldeXo7Q0FAYDAbExsbilVdeaTbQmNXU1KCmpsbytVarBQDodDrodLq2NrkRg94AANDrDR36ul2N+bOzBqxBw0dbxTqwBgBrYNbeOrS3fpJo5fzb1NRUxMfHo7q6Gi4uLli9ejVuv/32Jvfdu3cvzpw5g5iYGJSWluL111/Hzp07cfz4cQQFBTX7HgsXLsSiRYsabV+9ejWcnJxa09wWHbwk4ct0JXq5GTCnj6HDXpeIiIiAyspK3H///SgtLYVGo2n18a0OKbW1tcjKykJpaSnWrVuHFStWYMeOHejTp89Vj9XpdIiKisKMGTOwePHiZvdrqiclODgYhYWFbfqQzVl/+AKeX38Cw8I88MUjgzvsdbsanU6HhIQEjB8/HiqVqrOb0ylYA9bAjHVgDQDWwKy9ddBqtfD29m5zSGn15R57e3uEh4cDAOLi4nDw4EEsW7YMH3744VWPValUGDhwINLT01vcT61WQ61WN3l8R54sdnZKq9e2dR1d366INWANzFgH1gBgDczaWof21q7d66QYDAarXo+W6PV6pKamwt/fv71v2yG4mBsREZF8taonZcGCBZg8eTJCQkJQVlaG1atXIzExEVu2bAEAzJw5E4GBgViyZAkA4OWXX8awYcMQHh6OkpISvPbaa8jMzMRjjz3W8Z+kDXgXZCIiIvlqVUgpKCjAzJkzkZubCzc3N8TExGDLli0YP348ACArKwsKRX3nzOXLlzF79mzk5eXBw8MDcXFx2LNnzzWNX7kReO8eIiIi+WpVSPnkk09afD4xMdHq67feegtvvfVWqxt1o3DFWSIiIvmy6Xv31C/mRkRERHJj0yFFMo1K4Q0GiYiI5MemQ4qC9+4hIiKSLZsOKZLCPCaFKYWIiEhubDukmB45BZmIiEh+bDqk8C7IRERE8mXTIcU8BdnAewsSERHJjo2HFOMj+1GIiIjkx7ZDCjhwloiISK5sOqRwCjIREZF82XRIMV/u4WJuRERE8mPTIUVhvndPJ7eDiIiIGrPpkMK7IBMREcmXbYcUy717OrkhRERE1IhNhxQOnCUiIpIvmw4plsXcmFKIiIhkx8ZDivGREYWIiEh+bDukmB45cJaIiEh+bDqkWKYgM6MQERHJjk2HFC7mRkREJF82HVK4mBsREZF82XRIMWNHChERkfzYdEhRcAoyERGRbNl4SDE+MqMQERHJj02HFA6cJSIiki8bDynS1XciIiKiTmHbIcX0yJ4UIiIi+bHpkMLF3IiIiOTLpkNK/ZiUzm0HERERNWbTIaV+MTemFCIiIrmx6ZACTkEmIiKSLZsOKQpOQSYiIpItGw8pHDhLREQkVzYdUjgFmYiISL5sO6RwMTciIiLZsvGQYnzkFGQiIiL5semQUj8mhSmFiIhIbmw6pNSPSenUZhAREVETbDqkKBoMSWFvChERkbzYdEhBg4GzzChERETyYtMhxaonpfOaQURERE1oVUhZvnw5YmJioNFooNFoEB8fj59//rnFY9auXYvIyEg4ODggOjoamzZtaleDO5KiQU8K10ohIiKSl1aFlKCgICxduhRJSUk4dOgQbrvtNkydOhXHjx9vcv89e/ZgxowZePTRR5GcnIxp06Zh2rRpOHbsWIc0vr0arpLCkEJERCQvrQopd955J26//XZERESgV69e+M9//gMXFxfs27evyf2XLVuGSZMm4bnnnkNUVBQWL16M2NhYvPvuux3S+PaSOCaFiIhItuzaeqBer8fatWtRUVGB+Pj4JvfZu3cv5s2bZ7Vt4sSJ2LBhQ4uvXVNTg5qaGsvXWq0WAKDT6aDT6dra5Eb0dfWvVVurgxKGDnvtrsRc046sbVfDGrAGZqwDawCwBmbtrUN769fqkJKamor4+HhUV1fDxcUF69evR58+fZrcNy8vD76+vlbbfH19kZeX1+J7LFmyBIsWLWq0/ZdffoGTk1Nrm9ysGj1gLsHmLVugVnbYS3dJCQkJnd2ETscasAZmrANrALAGZm2tQ2VlZbvet9UhpXfv3khJSUFpaSnWrVuHWbNmYceOHc0GlbZYsGCBVQ+MVqtFcHAwJkyYAI1G02Hvo62sBg7sBACMnzABLuo2dyx1aTqdDgkJCRg/fjxUKlVnN6dTsAasgRnrwBoArIFZe+tgvhLSVq3+qWxvb4/w8HAAQFxcHA4ePIhly5bhww8/bLSvn58f8vPzrbbl5+fDz8+vxfdQq9VQq9WNtqtUqg49WdQqveXvdnZ2Nn0iAh1f366INWANzFgH1gBgDczaWof21q7d66QYDAar8SMNxcfHY9u2bVbbEhISmh3DcsNZTUHuxHYQERFRI63qSVmwYAEmT56MkJAQlJWVYfXq1UhMTMSWLVsAADNnzkRgYCCWLFkCAHj66acxatQovPHGG5gyZQrWrFmDQ4cO4aOPPur4T9IGDRdz42puRERE8tKqkFJQUICZM2ciNzcXbm5uiImJwZYtWzB+/HgAQFZWFhSK+s6Z4cOHY/Xq1XjhhRfwj3/8AxEREdiwYQP69evXsZ+ijbhOChERkXy1KqR88sknLT6fmJjYaNv06dMxffr0VjXqRuGKs0RERPJl0/fukXjvHiIiItmy8ZDCnhQiIiK5sumQAgCSuQ+FGYWIiEhWGFJMj5yCTEREJC8MKaaUItiVQkREJCs2H1LM2JNCREQkLzYfUswFEBw4S0REJCs2H1LMg1KYUYiIiOTF5kNK/cBZphQiIiI5YUhhTwoREZEsMaSYHtmTQkREJC8MKaZHRhQiIiJ5YUgxPXJ2DxERkbwwpHBMChERkSzZfEgx42JuRERE8mLzIYXL4hMREckTQ4rp0WDo1GYQERHRFRhSTI+cgkxERCQvDCnS1fchIiKiG48hxfTInhQiIiJ5YUgxPTKjEBERyQtDiimlsCeFiIhIXhhSTI+MKERERPJi8yHFjMviExERyYvNhxQui09ERCRPDCmmRy6LT0REJC8MKaZHXu4hIiKSF4YUy+yezm0HERERWWNIMT2yJ4WIiEheGFJMj4woRERE8mLzIQVczI2IiEiWbD6kmAvAjEJERCQvNh9SzNiTQkREJC82H1Isi7l1bjOIiIjoCgwppkfO7iEiIpIXhhTTIzMKERGRvDCkcDE3IiIiWWJIMT1y4CwREZG8MKTwLshERESyZPMhxYwDZ4mIiOSlVSFlyZIlGDx4MFxdXeHj44Np06YhLS2txWNWrVoFSZKs/jg4OLSr0R3Jsphbp7aCiIiIrtSqkLJjxw7MmTMH+/btQ0JCAnQ6HSZMmICKiooWj9NoNMjNzbX8yczMbFejrweOSSEiIpIXu9bsvHnzZquvV61aBR8fHyQlJWHkyJHNHidJEvz8/NrWwutMkgQAiWNSiIiIZKZVIeVKpaWlAABPT88W9ysvL0doaCgMBgNiY2PxyiuvoG/fvs3uX1NTg5qaGsvXWq0WAKDT6aDT6drTZCs6nc4yu0dXV9ehr92VmD+3rX5+gDUAWAMz1oE1AFgDs/bWob31k0QbR4waDAbcddddKCkpwe7du5vdb+/evThz5gxiYmJQWlqK119/HTt37sTx48cRFBTU5DELFy7EokWLGm1fvXo1nJyc2tLcZr13QoHTpQr8MVyPQd3YnUJERNRRKisrcf/996O0tBQajabVx7c5pPz5z3/Gzz//jN27dzcbNpqi0+kQFRWFGTNmYPHixU3u01RPSnBwMAoLC9v0IVtqy7Rl23C6VIHX7+mHqQMCOuy1uxKdToeEhASMHz8eKpWqs5vTKVgD1sCMdWANANbArL110Gq18Pb2bnNIadPlnrlz5+Knn37Czp07WxVQAEClUmHgwIFIT09vdh+1Wg21Wt3ksR19sphHDksKpU2fiMD1qW9XwxqwBmasA2sAsAZmba1De2vXqtk9QgjMnTsX69evx/bt2xEWFtbqN9Tr9UhNTYW/v3+rj70eeBdkIiIieWpVT8qcOXOwevVq/PDDD3B1dUVeXh4AwM3NDY6OjgCAmTNnIjAwEEuWLAEAvPzyyxg2bBjCw8NRUlKC1157DZmZmXjsscc6+KO0D6cgExERyUurQsry5csBAKNHj7bavnLlSjz00EMAgKysLCgU9R00ly9fxuzZs5GXlwcPDw/ExcVhz5496NOnT/ta3kHMs3vYlUJERCQvrQop1zLGNjEx0errt956C2+99VarGnUj1d8FmSmFiIhITmz+3j3mnhRGFCIiInlhSDE9sieFiIhIXhhSzLN7mFGIiIhkxeZDilkb17QjIiKi68TmQ4q5AIwoRERE8mLzIcUyu8fAmEJERCQnNh9SzJhRiIiI5MXmQwqnIBMREckTQ4pldg9jChERkZwwpJgemVGIiIjkhSHF9MjF3IiIiOSFIcV8uadzm0FERERXsPmQYsaeFCIiInmx+ZDCMSlERETyxJDC2T1ERESyxJBieuRibkRERPLCkMK7IBMREckSQ4rpkQNniYiI5IUhxfTIiEJERCQvDCmmRw6cJSIikheGFI5JISIikiWbDylmHJNCREQkLzYfUrgsPhERkTwxpJge2ZNCREQkLwwppkdmFCIiInlhSOGy+ERERLLEkGJ65LL4RERE8sKQYnpkRwoREZG82HxIMacUDpwlIiKSF5sPKTZfACIiIpniz2gT9qQQERHJi82HFC6LT0REJE8MKaZH9qQQERHJC0OKaUF8TkEmIiKSF4YUc1cK795DREQkKwwppkeDoVObQURERFdgSOE6KURERLJk8yFFZapAdR27UoiIiOTE5kOKg9L4WFat69yGEBERkRWGFEtIqevchhAREZEVmw8pjuxJISIikqVWhZQlS5Zg8ODBcHV1hY+PD6ZNm4a0tLSrHrd27VpERkbCwcEB0dHR2LRpU5sb3NEc7IwDZsvZk0JERCQrrQopO3bswJw5c7Bv3z4kJCRAp9NhwoQJqKioaPaYPXv2YMaMGXj00UeRnJyMadOmYdq0aTh27Fi7G98ReLmHiIhInuxas/PmzZutvl61ahV8fHyQlJSEkSNHNnnMsmXLMGnSJDz33HMAgMWLFyMhIQHvvvsuPvjggzY2u+OYL/eU19bBYBBQKKSWDyAiIqIbolUh5UqlpaUAAE9Pz2b32bt3L+bNm2e1beLEidiwYUOzx9TU1KCmpsbytVarBQDodDrodB03dkSn01l6UoQASiqq4Oqg6rDX7yrMNe3I2nY1rAFrYMY6sAYAa2DW3jq0t36SEG1bxcxgMOCuu+5CSUkJdu/e3ex+9vb2+OyzzzBjxgzLtvfffx+LFi1Cfn5+k8csXLgQixYtarR99erVcHJyaktzmyUE8Ox+JfRCwsLYOnioO/TliYiIbFZlZSXuv/9+lJaWQqPRtPr4NvekzJkzB8eOHWsxoLTVggULrHpftFotgoODMWHChDZ9yObodDokJCTA1cEeJVU6DB5+K3r5unbY63cV5jqMHz8eKpXt9SQBrAHAGpixDqwBwBqYtbcO5ishbdWmkDJ37lz89NNP2LlzJ4KCglrc18/Pr1GPSX5+Pvz8/Jo9Rq1WQ61u3KWhUqmuy8ni6mCHkiodqupg0yfj9apvV8IasAZmrANrALAGZm2tQ3tr16rZPUIIzJ07F+vXr8f27dsRFhZ21WPi4+Oxbds2q20JCQmIj49vXUuvI1cHY1Yrq+EMHyIiIrloVU/KnDlzsHr1avzwww9wdXVFXl4eAMDNzQ2Ojo4AgJkzZyIwMBBLliwBADz99NMYNWoU3njjDUyZMgVr1qzBoUOH8NFHH3XwR2k7S0jhNGQiIiLZaFVPyvLly1FaWorRo0fD39/f8uebb76x7JOVlYXc3FzL18OHD8fq1avx0UcfoX///li3bh02bNiAfv36ddynaCdXtTmk2PYobiIiIjlpVU/KtUwESkxMbLRt+vTpmD59emve6oZyUbMnhYiISG5s/t49QP3lHi6NT0REJB8MKQBcHHi5h4iISG4YUsCBs0RERHLEkIL6MSlahhQiIiLZYEhB/eye8hpe7iEiIpILhhTwcg8REZEcMaQAljsfM6QQERHJB0MK6ntSLlfWXtNaMERERHT9MaQACPZwhCQZe1KKKmo7uzlEREQEhhQAgINKiSAP472H0gvKO7k1REREBDCkWET4uAIAzjCkEBERyQJDikm4jwsA4CxDChERkSwwpJiYQwov9xAREckDQ4qJOaScKSjr5JYQERERwJBiYQ4p+doaaHmjQSIiok7HkGKicVDBV6MGwEs+REREcsCQ0kCknwYAcDJX28ktISIiIoaUBvoEGEPKiYsMKURERJ2NIaWBPv6mkMKeFCIiok7HkNKAuSflVG4Z9Abew4eIiKgzMaQ00N3LGQ4qBap0epwvqujs5hAREdk0hpQGlArJMniW41KIiIg6F0PKFcyXfI5dLO3klhAREdk2hpQrDAhyBwAkZ5V0ajuIiIhsHUPKFWJD3QEARy+UQKc3dG5jiIiIbBhDyhV6eLtA42CHap0Bp3J5Hx8iIqLOwpByBYVCQmyoBwAgKbO4k1tDRERkuxhSmhAbYgwphzkuhYiIqNMwpDRhYIg7AODIhZJObQcREZEtY0hpQm8/VwBAdnElqnX6Tm4NERGRbWJIaUI3FzU0DnYwCCCjkCvPEhERdQaGlCZIkoQIX2NvSnpBeSe3hoiIyDYxpDQjvJsLAOAMQwoREVGnYEhpRriPMaScZUghIiLqFAwpzQj3NYYUXu4hIiLqHAwpzTBf7skorEAdl8cnIiK64RhSmhHo7ggneyVq9QYcucA7IhMREd1oDCnNUCgkTO7nDwBYsetcJ7eGiIjI9jCktODxUT0AAJuP5+HcJY5NISIiupEYUlrQy9cVYyN9IATwzcHszm4OERGRTWl1SNm5cyfuvPNOBAQEQJIkbNiwocX9ExMTIUlSoz95eXltbfMNNX1QEADgp6O5EEJ0cmuIiIhsR6tDSkVFBfr374/33nuvVcelpaUhNzfX8sfHx6e1b90pRvf2gZO9EjklVUjJLsG+c0V49tsj0FbrOrtpRERENzW71h4wefJkTJ48udVv5OPjA3d391Yf19kcVEqMi/LFj0cuYn1yDj7fmwkACPZ0xDPjenVy64iIiG5erQ4pbTVgwADU1NSgX79+WLhwIUaMGNHsvjU1NaipqbF8rdVqAQA6nQ46Xcf1YJhf62qvOSXaGFLMAQUATudpO7Qtnela63AzYw1YAzPWgTUAWAOz9tahvfWTRDsGWkiShPXr12PatGnN7pOWlobExEQMGjQINTU1WLFiBb744gvs378fsbGxTR6zcOFCLFq0qNH21atXw8nJqa3NbTMhgA9PKXCypP7qmL+TwN/76yEEIEk3vElERESyV1lZifvvvx+lpaXQaDStPv66h5SmjBo1CiEhIfjiiy+afL6pnpTg4GAUFha26UM2R6fTISEhAePHj4dKpWpx34KyGkx7fy8uldcCAJQKCSkv3IbXE87gu8MX8eOcYQj2uPEBqiO0pg43K9aANTBjHVgDgDUwa28dtFotvL292xxSbtjlnoaGDBmC3bt3N/u8Wq2GWq1utF2lUl2Xk+VaXjfQU4WEeaNgEMD4N3egqKIW6YVV+D75Ispr6rDnXAkeHObW4W27ka5XfbsS1oA1MGMdWAOANTBrax3aW7tOWSclJSUF/v7+nfHW7eLuZA9PZ3v0CTCmwQ3JOSirrgMAnM4v68ymERER3XRa3ZNSXl6O9PR0y9cZGRlISUmBp6cnQkJCsGDBAuTk5ODzzz8HALz99tsICwtD3759UV1djRUrVmD79u345ZdfOu5T3GB9A9yw60whPms4kJYhhYiIqEO1uifl0KFDGDhwIAYOHAgAmDdvHgYOHIgXX3wRAJCbm4usrCzL/rW1tXj22WcRHR2NUaNG4ciRI9i6dSvGjh3bQR/hxovv6dVo25l847L57yem45FVB1Gt09/oZhEREd1UWt2TMnr06BZXXl21apXV188//zyef/75VjdMzkZGeGNAsDtSskss24oqapFZVIG3E86gVm/Ab+mFGBvl23mNJCIi6uJ47542kCQJf5vQ2/K1j6txkO/Hu86hVm8AAJzK4+UfIiKi9uiU2T03g1sivPH69P7QONjh20MXsPVkPr7cV3+ZiyGFiIiofdiT0g6/jwvChL5+iPRzbfTcqVxtJ7SIiIjo5sGQ0gFmDe9uCSpezvYAgHOFFRw8S0RE1A683NMBurmqsempW7E/oxiB7o64673dKKnUIb2gHP0Cu/YCb0RERJ2FIaWDKBSSZWpypJ8r9p0rxqm8Mpy4qMWhzGL4uzni93FBSM0phbPaDqN6devkFhMREckbQ8p1EB3ohn3nirH055MoNN3rBwCWbTtj+ftPf7mFvSxEREQt4JiU62D2rT0Q6O5oCSh39Q/A0DBPq33+u/mU5e+1dQaUVNaCiIiI6rEn5Trw0Tjgy8eG4tlvUzC4uyf+PjkSAJCWXwYhgLve3Y1dZwqx9UQ+xvXxxV+/SUHCiXz8+JcRiPRr+S6Rx3JKEeLlBI0Db3hFREQ3N/akXCdh3s74/skRWHB7FCRJgiRJiPTTIMpfg4dHhAEA/v79USRlXsbG1FzU6g3YkHyxxddceygbd7yzGwu+S70RH4GIiKhTMaR0gnnje6G3rysKy2txz/I9lu1bT+Y32re8pg4Gg0BplQ7PrTsKANiYmgu9oflbExAREd0MeLmnEziolHjn/oG4Z/kelFXXWbanF5Qjo7ACYd7OSDiRjzcTTuNkrhZ39Q9AsKej1Wuczi9DlH/Ll4aIiIi6MoaUTtLL1xWrHh6MmZ8cgJeLGn5uDjiQUYxtJ/NRVavHGwmnLftuPp6HMC9nq+MPZV5mSCEiopsaL/d0orhQT+yefxs2PnULJvfzAwD8eOQi3v01HQDwiGnsSm2dAWn5xnsB3TcoGABwOPNyJ7SYiIjoxmFI6WQezvZwdVBhXJQvAODohVLU1BkQ4umEf90RhbGRPpZ9A9wcMCXGHwBwKLO4U9pLRER0ozCkyESwp5PVjQrH9/GFJEmIDfWwbIsN9cCAEHcoFRKyi6twLKcUpZU6GDiIloiIbkIMKTJi7k0BjCEFAGJD6kPKoFAPaBxUuMPUm/LkV4cxYPEvWPLzyVa/V0p2CVKyS9rXYCIiouuIIUVGJpnGpXi7qDHI1IPSP9gNdgoJACy9Ko+P7AkAyCquhBDAZ3sykVtahfSCMsz89AD2nStq8X0qa+vwwMf7MOOjfdBW667XxyEiImoXzu6RkX6Bblj50GD4ahxgpzTmRyd7Oyye1g+5JVWINt3rp0+ABuOifLH1ZD7cHFUordLhwx3ncLGkCjtPX8LO05dw4B9j4aNxaPJ9zl2qQEWtHgBwJLsEw7q735DPR0RE1BoMKTIzpsFAWbMZQ0IabVv2hwHILKpESWUt7l+xH6sPZAENhqY8800KPpk1GAkn87Ej7RIm9/PDONMlpHOFFZb9krMYUoiISJ4YUrooZ7Ud+gRoIIRAXKgHkhpMSXZQKbDnbBGGvrIVWtNicQfOF9WHlEvlln0PZ10G0B3Z5cbLRz19eWdmIiKSB45J6eIkScJTYyMsXz80vDvemRELSQK01XWW8SzZxVUordKhTm/AuUv1PSmJaZcw+4vDeD3VDtM/2o8q02UgIiK6uZXX1GHS2zvxwIp9ONvgl1c5YUi5CYyM8MaQME8oFRJ+NzAQ4/v44oMH4/DU2AgcemEcAt2NS+r/9ZsU9P7XZvx4xPpGhomnCwEAxRU6/HgkB0cvlKC2ztDs+wkhsCk1F/vOFeHbQ9l445c01NQ1H25Kq3T4LulCi69JREStJ4SAEG1bhmL3mUs4lVeG39KLMHnZLmw+ltfBrWs/Xu65CUiShJUPDUZheQ1CTcvnT+zrh4l9jbOF+gZokFNShe2nCqyO89Woka+tgZezPXo4VuNgoQLzTXdYfnpsBHr5uiItT4tnxvWCQiFh87E8XK6shYeTPZ786rDVa3m7qDFrePcm2/d/287gk90ZuFRegydG9ezgT09EZLvmfp2MfWeLsPGpW+Hn1vRkiebsOVs/E1Rtp8DAEPcObl37MaTcJJzVdnBWN/3P2TfADb+caHyH5RUzB2PnmUuYMSgAGzcn4GBhfcfa98kXUFRei8paPQZ198SwHl54ek0yauoMmGQKPw1tPZnfbEg5eqEEAHAgo5ghhYionTKLKrDofycwvKcXNh7NBQB8d/gC5owJv6bj0wvKkZJdgt1njL3oHzwYi0g/DXybmRHamXi5xwb0DWj6RoTRQW6YMyYcrg4qaOyB2bd0h6NKCcA4hqXSND5ld3ohMosqUGO6XLPtlDHwLJ7WD9ufHQUA2HeuqMk1V4QQOFNgvNZ59ELpNXdLVuv0SDiRj8rauqvvTER0Eyur1uE/G0/gWE4pAOCT3RnYfqoA/95Yv5DnhuQcy/fXoxdKMO/bFJzM1TZ6rZo6PWZ9egB/W3sE5worIEnA0DAvdPd2brSvHDCk2IC+gfUhZeqAACgk4P6hjac1Pz+xF04unoQIHxer7TtPX0J6Qf2gKp3e+B8h0s8VPbq5oGc3Z+j0Aj8k50B/xRL9RRW1KKk0hpfC8hrkaauvqc0rfzuP2Z8fwsc7M67tQxIR3aQ+3HEOH+/KwAsbjgEA0vLKrJ5XSMCZgnIcyzGGkte2pOH7wzmYvGwXfjleP84kp6QKH+88h5ySKss2L2c1PJztb8CnaBte7rEBfhoHRPlrkK+txkt39sWCyVHwcFY1u//wnl6W3g8AOJVXhr1NrGLby8d4r6FxfXxxdsc5/OuH4/j20AV89sgQeJpO+obhBgDueX8PBnX3xNJ7ouFk3/zpd/yi8TcGuY44JyJqK53egPnfHUWQuyN+FxuET3afw9AwL0zo6wu1ndJq3zq9AWuTsgEYb2eSV1qN0/n1IWVyPz8IAWw+noe7l/+GP48Oxy7TZRwAeOLLJDw3MRIZheX49tAFy3bz0hUPj+h+fT9sOzGk2ABJkrD2iXjo6gzXlJjje3rjs72ZsFcqEOzpiLOXKvD53kyrffzdHODmZAw6Dw8Pw9mCCuw5W4jUnFI8uGI/1j4RD2e1nVXYAYCLpdX48chF6IXAuzMGQpKkJtuQWVQJACgou7aeFyKiruK39EJ8fzgHAPDZ3kyUVunw5b4sONkr8buBgfjXHX2wen8WhoR5oqCsGvnaGsuxn+89j8uVOigVEo4vmggHlRJZRZW4WFqFoxdK8X/bzgAAAt0dMSLcC98euoD/bj4FAJAkQCFJ6BfohjV/GobC8hr4uspvHEpDDCk2wkVtB6ivbd/RvbthSow/YgLdUFZdh3d/TW+0Ty/f+js2+7k5YMWsQUgvKMcfPtqLE7larNpzHnPGhCPdlPjNy/cDxv8oG4/mYnI/P+wyTX9ecnc0FKY1XYQQOG9aFfdSWQ2IiOTmwx1nsfdcEf5vxkBoHJrvmc4trcKC71MxY0iIZcZlw5mWpVU6+LiqoZAk5Gmr8dX+LGQVV2LXmUI4qpTwdjX+YunpbI/iilq8n3gWABDh4wIH0xjCEC8n/Dj3Fjy08gAS0y4BMN6k9sU7+iDCxxXbTxVAbxB4ZnwEhnQ3LlchSRL83RyvS206EkMKNeKgUuK9+2MBAOcLK6xCioeTCpcrdYj0c210XLiPC16Y0gfPfJOCj3edw8z4UKSbLtfMvjUMXx/IxtgoH6iUCnyyOwMf7jiHVNNAsPieXpg2MBAAUFxRi7Ia44DZAlNIqdbpcSS7BLGhHlApOZSKiG6szcdysXzHORRX1OCu/gFYnngWBgF8l3QBD48Ia/a4d7enIzHtEk7nlcHNUYXEtEv4Lsl42UUhGcPHilmD0C/ADf/dfAof7jxnuVxTpdMju7gKge6OeH16f8z4eJ/ldfs0MSHi6bERlpAyunc3KBQSZo/sgdkje3RkKW4ofrenFnX3drYsBgcAj93aA5IEyxL7V7qzfwB6dHNGSaUO9324D/vOFQMAbo3oht/+fhtentoPt0R4A4AloADGgV7VOuNsovOmSz0AUFZdh2qdHm9vPYP7PtqHyct24cTFxiPWiYgAYOGPx/HMmuRGg/ivpDcIHDxfDJ3egH9tOIaBL/+Cka/+iqTM4kb7CiHwn00ncSS7BNnFVXjvV2NAAYD1yTnNvkdplc5yWediaTUeWLEfH+w4a7nB6/FFk7B3wVjEBLlDoZDw0IjuUJp6lF0d7HDvoCDcEeOPH+eOQHxPL8yMD7W8dh//xiFlYIgH5o4Jx9QBARgR7t1yoboI9qTQVT0+qgde/OE4fDVqPDm6Jx69JczSzXglpULCi3f0wZ8+T8IJ0/S3u2MDERNUf0+gQaEeUCokq28iOSVV+NeGY7gnLgj7z1l/kyjQ1mDvWeNvFukF5Zj/3VH87y+34GSuFrM+PYDHRxnbRES2Z+GPx3H0Qgm+fGwozuSXY9We8wCAh0aEYUCwe5PHCCHw7Lcp2JBy0XJHeQC4XKnDkk2nsO7Pw632zyisQHZxFVRKCbdH++OHlIuW8R1HL5QivaAcQggsTzyL384WwtNZDRe1EmXVdajS1a/G3fB73m2RPnC0t/4+6u/miAl9fPHzsTw8MDQUf58cafX8v+7og8yiSuw5W4jRvbs1+dn+NrH3NdWtq2BIoav647BQONnbITrQDZIkNRtQzEb39sGvz43G53vOI8LXFffEBloNkHV1UKFfgAZHLhh7Ul6YEoVXNp3E2qQLWJt0odHrXSipxMnc+tHsxy6WorRShye+TEJBWQ0W/3SCIYXoJlBbZ4BBiKt+jzGrrK3DF/syTb0il/FjSv0tPw6dL0Y3VzX8NA6W3gmz5TvOYoNpX3NAiQv1QOqFUhzKvIw/frIfo3t5w8uUKcyXUIaEeeL16f0R4O6IUE8n/HIiH9tPFeCf61NxLKfU0kPScKArADx2SxhW7M6AJAHvzBiIAxnFeGBoKJqy5O5ojOntg6kDAxo9p1IqsPKhwaiorYNrC+NgbiYMKXRVkiTh93FBrTom0N0RC26Pavb5YT28cORCKbxd1Hj0ljAoFRIW/e9Ek/vuOlOIWr0B7k4qeDjZI6OwArvSL1lmAAHG34yamikkhMDWkwXo0c0ZPbu5NHqeiORBCIHpH+xBQVkNEuaNMg72b0J2cSXOFJThtkhfpF4otfRO7DlbiP8drQ8pb/xyGv/eeBJDwzyx6uEhll6LhBP5eG1LGgDj7TwKy42BYu5t4dh6Ih9f7c/CrjOF2HWmEH+KlDAFQOJpY0gZ1asbVEoF5k8y9nBE+Lpgd3oh9mcYe38HhXrgr+N7oVZvQHWtHjqDgLO9EmN6+2BQd+N4urFRvrgjpnEAMXN3sse9g4ObfV6hkGwmoAAMKdRJ7uwfgJW/ncd9g4MgSRIeHhGGO2ICcPZSOf7wkXFwmEopQacX2Gpa0j860A2B7o7IKKzAKw1WWgSAYzlaFJbXYES4N+ztjEOtDAaBBd+n4ptD2YjwcUHCvFE39kMS3aT2pBfCR+OAcJ+OC/5nCsotvasHzxdjTG8fq+fNg+dnf34I2uo6fPbIEKvxaV/szURtnQEuajuU19RfZtmfUYyRr/0KH1c1npvYG8+sSYYQxh7iKTH+mPHxPoR5OWNkRDdE+rni6IVSaKt1yCyqxI+ZCqi3p1suN4++ok1xoZ74ZNYgPPnVYUT6uWLlw0OaDVeT+vl3WK1sCUMKdYp+gW448fJEq27Ybq5qdHNV46nbwrE7vRDdvZ3x/eEcy1orA4Ld0d3LGWsOZuNiqfX6KXe+uxsAEOrlhI9nDkIvX1cs33EW3xwyLoJ0pqAcReU18HK5xnnYDdTU6fHP9ccwKNQDfxjSeKVeIlty9lI5HvhkPwLcHLF7/phm1zq60p6zhdA4qNAv0K3J539Lr1+ALOn8ZYzp7YNqnR6SBCRlXsZDKw9a3Un96/1ZMDS4zYb5Nh4zhgTj4131K1U7qpS4VFaDS2U1eGjlQQDA4O4eePHOPlApFfhhzgj4uBovCfm7OeJ/f7kFJZW1GPnqr8irqsM7v54DAIyL8m20GjdgnBRw8J/joLZTXHMt6Npxdg91Gjtl0/+p503oje+fHNHo8kxMkDuGhHlavg7zdsaQ7p5W+2QWVWLxTydQUFaN965Y3yUlu6TRe21KzcXIV3/Fyj31i9UJIfDJ7gxsPma8cVfCiXysS7qAv3+fiqyiSlTV6jF/3VGr5aY7WkVNHZYnnkXBNd5GgOhGOXqhBEIYB7unZJdg49Fcq/DQlLOXyvHgiv34/Qd7kHfFLxgnLmrx9JpkqwUjD2UW41JZDca+sQPj39yJZVvPoLbOADuFhFAvJwDGsSRN3Th1dG8fOJsu7cQEuWH3/DH4/JEh6OZq/AXFUaXE69P7W5YyiAlyb3T3YHcne7x4RxT8nQRG9/LGsj8MwMcz45oNIQ4qJQPKdcKQQrJl/qYCAE72SgwK9UCQhyMm9fVD/yA3fD17GOK6e1j2MffK7DlbhIU/HkdlrR4Dgt1xT6xxPE1Kdglq6vQoN63B8uW+TDz51WFkFVfiv1tOI8e4fhx+OZGPxT+dwNzVycgsqkByVonlPd7edhqbUnPxzaFs/OmLJJzJt76HRkdZsSsD/918Cq+arp0TdbQCbTVe23IKReWtWzDxdH79KtIPrTyIOasPY9H/jltec+PR3EY3Bt2QnAODAKp1Biz9+SR+OZ6H935Nx75zRVj4v+P4IeUiMkwLOAJAclYJ/vpNCnJKqpBVXGkZ85EwbxR2PDcG/YPcUGcai2KnkCyXWOztFIgL9cCHfxyE8X18sfzBOHi5qDGyVzd88GAsevu64pW7+yHU6+o305va3x9/76/Hx3+MxdQBgQwhnYSXe0i2ujW4NDNvfC/Lkv4f/DHOsj28QW/LzPhQ7D9XjBO5WmxKNfZy/HNKFE7nl+G7wxfwzvZ0fLDjLHR6gfgeXkjKvAwACHBzwMXSanxzTonHhMD7ph6YOoPA67+cRlZR/TfP9ck5MDSYRjjv2yP4Yc4Iy2q53yVdwJbjeXhmXC8YhIC3i9rqtzTzXUqv9g3vkGmthoPnG6/ZQDcvg0FAL8R1WbCwqlaPdUnZmBITAE9ne7z043H8fCwPFTV62CkknCuswFv3DYCbo3FQZn4V8Ny6VBzKKsFfx/XCPabB8w2DuXkV6a8PZMFOIeHbQxdQpdPD20WNV37XDyFeTth+qgAf7zpnOWZDykXLzBp7pQK1euteGPOYkt3phZAkwHxFZ1gPT4SZ7tT7+Kie+MvXxrVQ7hoQgOziShw8fxlxIR5wUClxS4S3ZT0ms7hQT2z568gOrCjdCAwpJFv9At3gZK9E3wANHhrevcl9enSr/41oZK9u8HZRW9ZnuSc2CIO7e8KpwVoE5js4m2+YOC7KF//5XT8MX7odmeXA98kXceRCKeztFKitM+B/R+pnC5iXpf75WP1lntScUpy9VI4IX1ccOl+M59YdgUHA0g2tUkp4fGRPPDuhFwDgwU/243xhJX5+5lbLUtqr92fhsz3nsWLWIAR7OkEIgSOmS1OZRZUoLK+BdxvG0lDX8l3SBby65RSc7O2w5ZmRlgHglytqkVlc2eyaH4Dx8uD5ogr08dc0G4Df2noaH+08h+SsEiy4PQoJpnN0Y2qu5fYTT3yRhE8eGgSVBHx7Tol0rfGS5xf7Mi0hpWFPiplBGO9BAwDO9koUltdg7upkqO0UltWjHVVKTO7nh59Sc9Gzmwtq6/Q4e8n4C8CQME9U1tZhcj9/JGeVWKYFv33fAKzacx7JWSV4cFj9lN3bo/1xW6RxEKuDSonXtpzCwfOXMTbKemArdX2tjus7d+7EnXfeiYCAAEiShA0bNlz1mMTERMTGxkKtViM8PByrVq1qQ1PJ1nRzVePQC+OwevYw2DXzm2VEg3sIDQvzwh0x/lApJXg4qfCP243TBHv7ukKlNH7jvn9oCDY+dQt6dHNGmLczlt4TDV+NA6JMy/y/kWC8Odf0uCBMbzDt2svZHpP6Ge+7UXPF9XfzZaSn16TAIABvF2OPj9pOAZ1e4N1f07E7vRDJ2SX4Lb0IOSVV2GFad+FyRS3+sT4Vafll+HK/8Zv8+aJKaKvru8sPm3p8qOsQQmDpz6fwfmLj+141Ze/ZIjy79gjytTXIKKzASVPQFkLgoZUHMO293yxjpBo6kFGMl/93AiP+ux1T/m83vtyX2WgfwLj+yDrTGkQJJ/Kx5kCW5XJJw/tj7T1XhKH/2YYv9mXhbIOFnU/kalFbZ0BVrR7Zl41T/809Lovu6ose3Yzjwz54MA7JL07AxL6+qNUbUFZTZxkfct/gYLx53wCkLZ6En5++FV89NgzuppuUzp8UiZ/+civmjAnH3ydHGgfPzx+DqQMCsfKhwVj92NBG03YdVErLeipzx0Tg80eGtLg8PXVNre5JqaioQP/+/fHII4/g7rvvvur+GRkZmDJlCp544gl89dVX2LZtGx577DH4+/tj4sSJbWo02Q4n+5ZPURe1HbY9OwpKSYKjvRKhXs74Yc4t0DjaWWby2CkVeGdGLM5eKsfjI3vATqnAtnmjoDcIS/gZGOyGYxe1uFReC8DYwzIwxN2yuFxvP1fEBLphdYP3vjs2EN8fzsGRCyXwdLZHTkkVurmqsf3ZUcgurkKPbs54YcMxrEu6gG0nC1BTV7/y5M7Tl4zTsE2rYwLGHxZF5TXYaVqTwezg+WKM6t3N6hbuOSVVSEwrwD2xQde88JX5uKnv/oYJfX3xyu+iIYRA4ulL6BuggYdDwx4nA5SSZLmMdaWqWj1Kqmrh4WTfqveXm6bW1zmWo0W1vpkDrlFS5mV8sMN4I7hZ8d3h3MS01HxtNfK11fBzc0Di6QKr5/adK8KvaQWorTNYpuW+sukU/nc0F1F+rph7WwR+OnoRc1cnWx33zvZ0xPf0Rp3BgCAPJ+w7WwRntR3OXipHcYXx3C6rqcMbCacBwGrl55G9uiGzqAKZRZV4eeMpABJ6+bggT1sNbXUdTueXQQjj5RcvZ3usfHgwzhdV4s4Yf8y6oqfzrfsG4KmvUwAIvHHvAFwqq7aMAzHX28/NAeufHIG80mrEhdaPLQv3ccG8CfWrpro72WP4VZZ4d7RXYmSvpldgpa6t1SFl8uTJmDx58jXv/8EHHyAsLAxvvPEGACAqKgq7d+/GW2+9xZBCHeLKWUBN3XjL3AtiJkkS7JT1P5wGhrjji/3G6coqpYShPTzhZG+H1bOH4r+b0/DshF5wVNX/d/F0tsfYSF9jSMkuRVWtsXdlSrQ/XB1U6BNg/A1xQh9frEu6gJ+OXkS1rr4HZueZS0jKvIxPGlyrT8kqwW1v7LBc5/d2sUdheS0+3pWBVXvO49aIbvjnlChcrqjFn75IQnFFLapq9Xjs1qZvHqat1uGLvZn4fVwQfDXGcTHfJV1AYXkNvj2Yjecn9sY3B7Ox5OdTGBfli+X39zceV6XDXe/vQjdXNdY/ObzRD/GsokpMWrYTlbV6+LiqsfXZUS3eBbYh83ie5sJPR/lo51l8czAbyx+MQy9fVxSW1yBfW42+AfXTX9clXcC/N57AP2+PwvRBxsWzNh/LwxNfJmFoNwXMv4JdLKnCI6sOItLPFW//YWCz73kgoxh1egOGh3tb3eX2wuUq9L7ihpzJWZdx74d7odMLONkr4Wf69wl0d0ROSRVe/yXNcmnSLKu4ElnFldh4NBeuDiq8aQoa4/v4YuqAACz+6QTytTUY9+YOAMab1115+xoHlcJyHoZ4OmFslA9W/nYegLFHJNTTCRPf3mmZ9n9bZDccu1iG3emFOHKhBA6moBzh64KYIHfEBLk3WQsnezusmDXI8rW51+VKYd7OlnEmRE257mNS9u7di3HjxlltmzhxIp555plmj6mpqUFNTX0XpFZr7HfU6XTQ6XQd1jbza3Xka3ZFrAMQ7V//jTI2xB0qSUCn02FwiBvW/WkIAGPvgtpOgZo6A3p2c0Zf0zGpOaU4bRpMOD7K26qOQ0LdoFJKKDT10AR5OJp+YNbgnuV7AAB+GjXytDU412B2AwA8FB+KZdvTodML6PQC208VICX7Msqq6+rH1pwtxKxhTa9O+fKPx7HucA7S87V49Z5oAMDPqcZLBnUGgfWHjQEFME7nrK01tnFd0gXklFQhp6QKyZlF6BdgPc4h4USuZU2KgrIa/JSSg+lxgU22YcfpSziUWYKnbuuJNQcvYPmOczAIYPNTIyxd/R1h5Z5MfLQrA5/OjEMvXxe8ssn4uR5csR87/zYSf/r8EA5nleCD+wdYxi28vfU0Sip1eG7dUdgrgNuj/fD9YWNQTSuVoNPpUF5Thz9+sh9nL1XgVF4Z5o0Lh51CwpNfpyA+zBMje3nj3V/PIcLHGav2ZkGpkPDL0yOwpcH09I1HcjD784twUdvhvkFBuDcuEAu+T7X8G1bW6i3/9rPiQ/DKz9YBxdNZhSdH9cB/fk5DNxc1Cspq8NKPxtk00YEaLLs3GiqlAoXaMCz8yfi5zedpsIcjFJKEy5W1cHNUYc7oHvj7euOxr/++HyCAlb+dR98AVwS52UOvr8PjI8Pwt3WpAIBbexp7OHanF+JwZjEyCo2XeqL8XG/67xf8vmjU3jq0t36SEEJcfbdmDpYkrF+/HtOmTWt2n169euHhhx/GggULLNs2bdqEKVOmoLKyEo6Ojo2OWbhwIRYtWtRo++rVq+Hk5NTW5hI1SwjgxSQltDoJU4L1mBDU9H+Lt1KVOF8uYYSvAdPDDHghSYlynemupSqBl+P0uLKT4M1UJTLLjRuf6luHrTkKnCgxXmaK0BjwWG8D/nlIiTph3EcBgWE+Ar/rbsDlWkBnAJQS8NlpJXKrjPsEOwtkV0hwthP4zyDjglc5FcDP2Qr08xSIchdYdFgJvZDgqhJYHKdHUQ2wOLn530sWx9XBVQUsPaJEnul9fB0FKnTASH8DJgQKSBLw2WkFDhcpYK8QqDVIiNAYMLdv43UyzmqB/ztufL/B3gYcLKwfVzQ7Uo9+Hm3+1oO9+RLWZijQy01gSDeBz84oLe9zi58Bbx2r/5yTgvTYfMH4vLu9wIIBelTWAYsO1+/jYS/wjwF6/POQErUG42f/96A67M5TYPOF+nbf10OPjDIJBy4poJAEfB1g+TcxG+hlQHJR/THmOgGAShKY2t2AdRlKONkJjA0w4H9Zxra52AnM76/Hv5KM7VJKAvOi9XBVAW72QGUdYCcBr6cqkV8loZebATN6GuBpGlNtEEBykQQfBwFfR0CrA7zUQMOOMCGA7RcleDkAA0w3pknXAt5qwN30OnoBrDhlbP/sSANSiyV8err+kp5aYayhB8dy0zWorKzE/fffj9LSUmg0jXu5r0aWs3sWLFiAefPmWb7WarUIDg7GhAkT2vQhm6PT6ZCQkIDx48dDpbKdeyFciXUw1SBnK1IrXPDcvYMQ6N44PANAjiYDr245g1nj4zCmdzcklB/FRtNsn0duDccdY3o2OsY5/BIW/u8knh0fgTti/DGpoByrD2RjRE8vjOndDUqFhM8u7MUJ000U35kxABP6+DZ6nTvLarDop5Po66/BoyNCEffKr6ioMyBqyCiUVOnwwheHUVZdh9TLgI+rGnph7I0s00noPvAW7NqfBeAiQj2dkFlc2ej1/SPjcDQlyRJQACDf9PdN2UpERPTE3DE98d8TOwFUY+FdffGPDSeQXqZA3C2jLZeUAGMPy8vv7QVg7J1pGFAAwC04ErePrB/kWFWrx1vb0jG5ry9+PX0Ja5NysGpWXKPLJAaDgACw9M1d0ItqnCyRcLKk/vkKlRtqvLoBqL+M9ktO/Q/YkloJJ5U9EOTtCCANMYEapF+qwOVaPbKce6HWUH+cZ/hApJw+DaAG4d2ckX6pAltyHVBiuhxnEBJyq4z72tsp4GyvxOVKnVVAAWAJKACgExL2XXYGUI0nx/TC/UOCkfBqIqp1BsRH+OIP0wbgg7M7kVNSjdsiffGn6QMa/TuNHa/DpbJaq5ltZnc02tLYlGvYZ9KE+u8JQ6oN+Pz1nZaBtn+bFIkH4pu+Od7NhN8XjdpbB/OVkLa67iHFz88P+fnWqwLm5+dDo9E02YsCAGq1Gmp145iuUqmuy8lyvV63q7H1OkwIEnj79ltbrMEToyLwhyHd4Wlas+Xlaf1we0wAogPdEOLVdC/fuL4BGNe3fmZCn0AP/Pt3Hlb79PbT4ERuGRQScEuEb5NtCPRU4aOZgy1f9w9yx4HzxfjhaB6+2p+Fsuo6hPu4IKOwAgWmGRs+rsbLA9OW77McN39yJLafKsDp/DL8dVwvrE3KxqbUPKRdqsT688Yf6FNi/LHxqPHSkHmtio92ncfvB4XgYmk1FBIwdWAwvkvORVLmZXy2Lxv/nNIHgDFI/H39YRRV1FrWvDAbG+mDbacKcK6oEjohYdm2M9DVCXT3dsLKPZlYuScTdgoJdQaBN7edRYinE3w1DnhiVA+cL6rEgyv2I6ekyvJ6UwcE4IcGd749mVdmmfK68M4+WLr5lGUMRv9gdxzJLsHn+7IQ7Gn8t7prQCCSTaummpc/N1uxJxt52hq4O6nw6vT+uPv9PZaAonGws8zAGt7TC6tnD0O1To/If222HP/gsBB8uS/L8rW5FhdKjCuujojoBk9XR0ztH4hvDmVjdKQPVCoVbov0xRf7MnH/0NAmzwNPlQqerjemR1mlUiHQSYWvHhuK1JxSaBxU+H1c0HUfUyQntv590aytdWhv7a57SImPj8emTZustiUkJCA+Pv56vzVRh1MoJEtAAQAvFzWmxLT/xmG9TFOpowPd4HaNYzXiunvgwPlivJ9onEXSP9gda2YPw6WyGpwpKIO7kwrJWSX4t+lmjE72SrwxvT8mR/vj9uj6Nh+9UIpNqXl47ZczACS4OtjhpTv7wEmlxOZjefhq9lDM+vQALlfqsMo0GynKXwNntR3mjgnHw6sO4pPdGZAkCVH+rqis1WPXmUKo7RRY/+Rw/GN9Kg6ev4xwHxf8Pi4I204V4OD5Ytzxzm6cM62T0T+ofkCr+Tf2hoNP80qrcORCqVVAeXxkDyy4PQoPDgtFnV7gn+tTca6wAtnFVZAk4I7+AUjOLrGEmGfGRmB9cg5+PHIRmUWVcLJXYnK0P/zdHC2BTKWUMLmvH348movDppWG7x4YhIHB7vB3c0BuaTViQ9yx8K6+uOvd3wAYb5YJGKfEPju+Fz7ceQ7/N2MAAFhCiiQB98QGWtYSsbdTWAbxLpraF5Oj/TAywjg75Z9TovDYrWHXtCrqjTK0hxeG9vDq7GaQDWp1SCkvL0d6ev3c/4yMDKSkpMDT0xMhISFYsGABcnJy8PnnnwMAnnjiCbz77rt4/vnn8cgjj2D79u349ttvsXHjxo77FERd3O/jgnDofHGjqZwtGRvpg+WmgNLD2xkf/zEOjvZKhHg5WXp13J3s8cqmk3BUKfH5o0MQF+rZ6HUi/a0vqfxtfAR8XB3w6u9j8J/fRcPeToHB3T3xy4l8fLLbeOO22BBjT9CYSB/c1T8APx65iI92GnsiHFTGyx3zJ0UiwtcVT4zqiSMXDmPOmJ6WdW2yi6us3tM8zdast68r0vLLLL0q5h/urg52cFHb4XJlrWVxr8Gm+zfFhnpYBqA+PDwM3i5q3B0bhB9SLsJOIWFwmCf6Bbohp6QKns72+Ou4Xgh0d4SHkwquajvj1Nx7B8DLSYkfTaHFRW2HWcNDIUkS3pkxEMlZJZg5PBRqOyVuj/bD6fxyq8D3l7ERmDMmHAqFZBlMDQChnk4YEuZl+RwxgW6WxdocVEqru+s6qJSyCihEnanVIeXQoUMYM2aM5Wvz2JFZs2Zh1apVyM3NRVZWfRdnWFgYNm7ciL/+9a9YtmwZgoKCsGLFCk4/Jmqgm6sanzw0+Oo7NjCouye2zhsFwHj356aWUu/ZzQXf/Xk4urmqEeTR9CWCKL/6cV7RHgbMGGxcxE6SJNjbGbv1h/bwsrqZW8Peo5en9oWjSolcbTV2nr6Eap0BvX1dMdM0bmFslC9O/9u4bEGd3gCVUrLMXnFzVFmmXAPGRfSi/DUYG+WDF384jgeHhUJbpcOX+zNxqawGL0zpg1sjvFFeU2c1BgYAJvX1w7qkC4gOdMPfJxsX8rs13BtP3RaOQA9HuKiNAee7Pw+3Os7J3g5r/xyPylo9YkM8UFJeBSelAJR2+OyRwZbAMKi7JwY1uKHl+w/EoSnmSyFBHvWXsyP9NIhp0FvUcF0QImpeq0PK6NGj0dKEoKZWkx09ejSSk5Mb70xE7RLexK3jrzQwpOUfiEEejrgl3Btl1TrM8C9qcln1oQ3uPt3HX2P1tbuTPf77+xgYDAJ//TYFPx/Lw+Jp/ZpcJdhOqbCaXvuP2yMx/zvjdFd7OwWW3B1tOe6zR4ZY9runweq/AJpcHG1slA/WPhGPPv4aSy+FQiFZLQzWnMgGQc1ZbYfn++sxftxoBHpevb7NcbK3s6x109vPFUEejnB3UqGkUnfVfxMiMpLl7B4iunEUCglfPjYUOp2u0fgxsyj/+h/iM+NDmwwyCoWEt+8bgP/eY2hxFVrz2A5HlfUqob19XZu9/cG1kCTJcumnvTzUxkHH7dXD2wWF5cXoF+gGSZLwryl9cPB8seW+M0TUMoYUIroqpULCyocG41RemWV11qZIknTVZfLfvm8AXt2ShsVT+8FP42CZgRR1xdiYm8Hiaf2w71yRJZTcExfUqFeIiJrHkEJE12RMpA/GdEAPwNAeXlbjQgaHeWLj0VwMCL75LoH09nNttNYLEV07hhQi6lQv3tEHt4R7W911mogIYEghok7mq3HAjCEhnd0MIpKhto9SIyIiIrqOGFKIiIhIlhhSiIiISJYYUoiIiEiWGFKIiIhIlhhSiIiISJYYUoiIiEiWGFKIiIhIlhhSiIiISJYYUoiIiEiWGFKIiIhIlhhSiIiISJYYUoiIiEiWusRdkIUQAACtVtuhr6vT6VBZWQmtVguVStWhr92VsA6sAcAamLEOrAHAGpi1tw7mn9vmn+Ot1SVCSllZGQAgODi4k1tCRERErVVWVgY3N7dWHyeJtsabG8hgMODixYtwdXWFJEkd9rparRbBwcHIzs6GRqPpsNftalgH1gBgDcxYB9YAYA3M2lsHIQTKysoQEBAAhaL1I0y6RE+KQqFAUFDQdXt9jUZj0yehGevAGgCsgRnrwBoArIFZe+rQlh4UMw6cJSIiIlliSCEiIiJZsumQolar8dJLL0GtVnd2UzoV68AaAKyBGevAGgCsgVln16FLDJwlIiIi22PTPSlEREQkXwwpREREJEsMKURERCRLDClEREQkSzYdUt577z10794dDg4OGDp0KA4cONDZTWqTJUuWYPDgwXB1dYWPjw+mTZuGtLQ0q31Gjx4NSZKs/jzxxBNW+2RlZWHKlClwcnKCj48PnnvuOdTV1Vntk5iYiNjYWKjVaoSHh2PVqlXX++Nds4ULFzb6jJGRkZbnq6urMWfOHHh5ecHFxQX33HMP8vPzrV6jq9ege/fujWogSRLmzJkD4OY8D3bu3Ik777wTAQEBkCQJGzZssHpeCIEXX3wR/v7+cHR0xLhx43DmzBmrfYqLi/HAAw9Ao9HA3d0djz76KMrLy632OXr0KG699VY4ODggODgYr776aqO2rF27FpGRkXBwcEB0dDQ2bdrU4Z+3OS3VQafTYf78+YiOjoazszMCAgIwc+ZMXLx40eo1mjp/li5darWPnOtwtXPhoYceavT5Jk2aZLVPVz8XrlaDpr4/SJKE1157zbKPrM4DYaPWrFkj7O3txaeffiqOHz8uZs+eLdzd3UV+fn5nN63VJk6cKFauXCmOHTsmUlJSxO233y5CQkJEeXm5ZZ9Ro0aJ2bNni9zcXMuf0tJSy/N1dXWiX79+Yty4cSI5OVls2rRJeHt7iwULFlj2OXfunHBychLz5s0TJ06cEO+8845QKpVi8+bNN/TzNuell14Sffv2tfqMly5dsjz/xBNPiODgYLFt2zZx6NAhMWzYMDF8+HDL8zdDDQoKCqw+f0JCggAgfv31VyHEzXkebNq0Sfzzn/8U33//vQAg1q9fb/X80qVLhZubm9iwYYM4cuSIuOuuu0RYWJioqqqy7DNp0iTRv39/sW/fPrFr1y4RHh4uZsyYYXm+tLRU+Pr6igceeEAcO3ZMfP3118LR0VF8+OGHln1+++03oVQqxauvvipOnDghXnjhBaFSqURqaup1r4EQLdehpKREjBs3TnzzzTfi1KlTYu/evWLIkCEiLi7O6jVCQ0PFyy+/bHV+NPw+Ivc6XO1cmDVrlpg0aZLV5ysuLrbap6ufC1erQcPPnpubKz799FMhSZI4e/asZR85nQc2G1KGDBki5syZY/lar9eLgIAAsWTJkk5sVccoKCgQAMSOHTss20aNGiWefvrpZo/ZtGmTUCgUIi8vz7Jt+fLlQqPRiJqaGiGEEM8//7zo27ev1XH33XefmDhxYsd+gDZ66aWXRP/+/Zt8rqSkRKhUKrF27VrLtpMnTwoAYu/evUKIm6MGV3r66adFz549hcFgEELc/OfBld+UDQaD8PPzE6+99pplW0lJiVCr1eLrr78WQghx4sQJAUAcPHjQss/PP/8sJEkSOTk5Qggh3n//feHh4WGpgRBCzJ8/X/Tu3dvy9b333iumTJli1Z6hQ4eKxx9/vEM/47Vo6ofTlQ4cOCAAiMzMTMu20NBQ8dZbbzV7TFeqQ3MhZerUqc0ec7OdC9dyHkydOlXcdtttVtvkdB7Y5OWe2tpaJCUlYdy4cZZtCoUC48aNw969ezuxZR2jtLQUAODp6Wm1/auvvoK3tzf69euHBQsWoLKy0vLc3r17ER0dDV9fX8u2iRMnQqvV4vjx45Z9GtbMvI+canbmzBkEBASgR48eeOCBB5CVlQUASEpKgk6ns2p/ZGQkQkJCLO2/WWpgVltbiy+//BKPPPKI1Y05beE8MMvIyEBeXp5Ve93c3DB06FCrf3d3d3cMGjTIss+4ceOgUCiwf/9+yz4jR46Evb29ZZ+JEyciLS0Nly9ftuzTVeoCGL9PSJIEd3d3q+1Lly6Fl5cXBg4ciNdee83qUt/NUIfExET4+Pigd+/e+POf/4yioiLLc7Z2LuTn52Pjxo149NFHGz0nl/OgS9xgsKMVFhZCr9dbfSMGAF9fX5w6daqTWtUxDAYDnnnmGYwYMQL9+vWzbL///vsRGhqKgIAAHD16FPPnz0daWhq+//57AEBeXl6T9TA/19I+Wq0WVVVVcHR0vJ4f7aqGDh2KVatWoXfv3sjNzcWiRYtw66234tixY8jLy4O9vX2jb8i+vr5X/Xzm51raRy41aGjDhg0oKSnBQw89ZNlmC+dBQ+Y2N9Xehp/Hx8fH6nk7Ozt4enpa7RMWFtboNczPeXh4NFsX82vISXV1NebPn48ZM2ZY3TTuqaeeQmxsLDw9PbFnzx4sWLAAubm5ePPNNwF0/TpMmjQJd999N8LCwnD27Fn84x//wOTJk7F3714olUqbOxc+++wzuLq64u6777baLqfzwCZDys1szpw5OHbsGHbv3m21/U9/+pPl79HR0fD398fYsWNx9uxZ9OzZ80Y387qYPHmy5e8xMTEYOnQoQkND8e2338rqB+eN8sknn2Dy5MkICAiwbLOF84BaptPpcO+990IIgeXLl1s9N2/ePMvfY2JiYG9vj8cffxxLliy5KZaH/8Mf/mD5e3R0NGJiYtCzZ08kJiZi7NixndiyzvHpp5/igQcegIODg9V2OZ0HNnm5x9vbG0qlstHMjvz8fPj5+XVSq9pv7ty5+Omnn/Drr78iKCioxX2HDh0KAEhPTwcA+Pn5NVkP83Mt7aPRaGQZAtzd3dGrVy+kp6fDz88PtbW1KCkpsdqn4b/5zVSDzMxMbN26FY899liL+93s54G5zS39X/fz80NBQYHV83V1dSguLu6Qc0NO31PMASUzMxMJCQlWvShNGTp0KOrq6nD+/HkAN08dzHr06AFvb2+r899WzoVdu3YhLS3tqt8jgM49D2wypNjb2yMuLg7btm2zbDMYDNi2bRvi4+M7sWVtI4TA3LlzsX79emzfvr1RN1xTUlJSAAD+/v4AgPj4eKSmplr9BzV/E+vTp49ln4Y1M+8j15qVl5fj7Nmz8Pf3R1xcHFQqlVX709LSkJWVZWn/zVSDlStXwsfHB1OmTGlxv5v9PAgLC4Ofn59Ve7VaLfbv32/1715SUoKkpCTLPtu3b4fBYLCEuPj4eOzcuRM6nc6yT0JCAnr37g0PDw/LPnKuizmgnDlzBlu3boWXl9dVj0lJSYFCobBcArkZ6tDQhQsXUFRUZHX+28K5ABh7WuPi4tC/f/+r7tup50GrhtneRNasWSPUarVYtWqVOHHihPjTn/4k3N3drWY1dBV//vOfhZubm0hMTLSaMlZZWSmEECI9PV28/PLL4tChQyIjI0P88MMPokePHmLkyJGW1zBPPZ0wYYJISUkRmzdvFt26dWty6ulzzz0nTp48Kd577z1ZTb999tlnRWJiosjIyBC//fabGDdunPD29hYFBQVCCOMU5JCQELF9+3Zx6NAhER8fL+Lj4y3H3ww1EMI4Uy0kJETMnz/favvNeh6UlZWJ5ORkkZycLACIN998UyQnJ1tmrSxdulS4u7uLH374QRw9elRMnTq1ySnIAwcOFPv37xe7d+8WERERVtNOS0pKhK+vr/jjH/8ojh07JtasWSOcnJwaTbm0s7MTr7/+ujh58qR46aWXbugU5JbqUFtbK+666y4RFBQkUlJSrL5PmGdo7NmzR7z11lsiJSVFnD17Vnz55ZeiW7duYubMmV2mDi3VoKysTPztb38Te/fuFRkZGWLr1q0iNjZWREREiOrqastrdPVz4Wr/H4QwTiF2cnISy5cvb3S83M4Dmw0pQgjxzjvviJCQEGFvby+GDBki9u3b19lNahMATf5ZuXKlEEKIrKwsMXLkSOHp6SnUarUIDw8Xzz33nNX6GEIIcf78eTF58mTh6OgovL29xbPPPit0Op3VPr/++qsYMGCAsLe3Fz169LC8hxzcd999wt/fX9jb24vAwEBx3333ifT0dMvzVVVV4sknnxQeHh7CyclJ/O53vxO5ublWr9HVayCEEFu2bBEARFpamtX2m/U8+PXXX5s8/2fNmiWEME5D/te//iV8fX2FWq0WY8eObVSboqIiMWPGDOHi4iI0Go14+OGHRVlZmdU+R44cEbfccotQq9UiMDBQLF26tFFbvv32W9GrVy9hb28v+vbtKzZu3HjdPveVWqpDRkZGs98nzGvoJCUliaFDhwo3Nzfh4OAgoqKixCuvvGL1A1wIedehpRpUVlaKCRMmiG7dugmVSiVCQ0PF7NmzG/1i2tXPhav9fxBCiA8//FA4OjqKkpKSRsfL7TyQhBCidX0vRERERNefTY5JISIiIvljSCEiIiJZYkghIiIiWWJIISIiIlliSCEiIiJZYkghIiIiWWJIISIiIlliSCEiIiJZYkghIiIiWWJIISIiIlliSCEiIiJZYkghIiIiWfp/5PzjpkGQB7cAAAAASUVORK5CYII=",
      "image/svg+xml": [
       "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n",
       "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n",
       "  \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n",
       "<svg xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"398.801786pt\" height=\"297.190125pt\" viewBox=\"0 0 398.801786 297.190125\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n",
       " <metadata>\n",
       "  <rdf:RDF xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n",
       "   <cc:Work>\n",
       "    <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/>\n",
       "    <dc:date>2023-04-24T22:07:22.387333</dc:date>\n",
       "    <dc:format>image/svg+xml</dc:format>\n",
       "    <dc:creator>\n",
       "     <cc:Agent>\n",
       "      <dc:title>Matplotlib v3.6.3, https://matplotlib.org/</dc:title>\n",
       "     </cc:Agent>\n",
       "    </dc:creator>\n",
       "   </cc:Work>\n",
       "  </rdf:RDF>\n",
       " </metadata>\n",
       " <defs>\n",
       "  <style type=\"text/css\">*{stroke-linejoin: round; stroke-linecap: butt}</style>\n",
       " </defs>\n",
       " <g id=\"figure_1\">\n",
       "  <g id=\"patch_1\">\n",
       "   <path d=\"M 0 297.190125 \n",
       "L 398.801786 297.190125 \n",
       "L 398.801786 0 \n",
       "L 0 0 \n",
       "z\n",
       "\" style=\"fill: #ffffff\"/>\n",
       "  </g>\n",
       "  <g id=\"axes_1\">\n",
       "   <g id=\"patch_2\">\n",
       "    <path d=\"M 30.103125 273.312 \n",
       "L 387.223125 273.312 \n",
       "L 387.223125 7.2 \n",
       "L 30.103125 7.2 \n",
       "z\n",
       "\" style=\"fill: #ffffff\"/>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_1\">\n",
       "    <g id=\"xtick_1\">\n",
       "     <g id=\"line2d_1\">\n",
       "      <path d=\"M 46.335852 273.312 \n",
       "L 46.335852 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_2\">\n",
       "      <defs>\n",
       "       <path id=\"m2c47ecf537\" d=\"M 0 0 \n",
       "L 0 3.5 \n",
       "\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"46.335852\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_1\">\n",
       "      <!-- 0 -->\n",
       "      <g transform=\"translate(43.154602 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-30\" d=\"M 2034 4250 \n",
       "Q 1547 4250 1301 3770 \n",
       "Q 1056 3291 1056 2328 \n",
       "Q 1056 1369 1301 889 \n",
       "Q 1547 409 2034 409 \n",
       "Q 2525 409 2770 889 \n",
       "Q 3016 1369 3016 2328 \n",
       "Q 3016 3291 2770 3770 \n",
       "Q 2525 4250 2034 4250 \n",
       "z\n",
       "M 2034 4750 \n",
       "Q 2819 4750 3233 4129 \n",
       "Q 3647 3509 3647 2328 \n",
       "Q 3647 1150 3233 529 \n",
       "Q 2819 -91 2034 -91 \n",
       "Q 1250 -91 836 529 \n",
       "Q 422 1150 422 2328 \n",
       "Q 422 3509 836 4129 \n",
       "Q 1250 4750 2034 4750 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-30\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_2\">\n",
       "     <g id=\"line2d_3\">\n",
       "      <path d=\"M 93.387236 273.312 \n",
       "L 93.387236 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_4\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"93.387236\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_2\">\n",
       "      <!-- 2500 -->\n",
       "      <g transform=\"translate(80.662236 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-32\" d=\"M 1228 531 \n",
       "L 3431 531 \n",
       "L 3431 0 \n",
       "L 469 0 \n",
       "L 469 531 \n",
       "Q 828 903 1448 1529 \n",
       "Q 2069 2156 2228 2338 \n",
       "Q 2531 2678 2651 2914 \n",
       "Q 2772 3150 2772 3378 \n",
       "Q 2772 3750 2511 3984 \n",
       "Q 2250 4219 1831 4219 \n",
       "Q 1534 4219 1204 4116 \n",
       "Q 875 4013 500 3803 \n",
       "L 500 4441 \n",
       "Q 881 4594 1212 4672 \n",
       "Q 1544 4750 1819 4750 \n",
       "Q 2544 4750 2975 4387 \n",
       "Q 3406 4025 3406 3419 \n",
       "Q 3406 3131 3298 2873 \n",
       "Q 3191 2616 2906 2266 \n",
       "Q 2828 2175 2409 1742 \n",
       "Q 1991 1309 1228 531 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "        <path id=\"DejaVuSans-35\" d=\"M 691 4666 \n",
       "L 3169 4666 \n",
       "L 3169 4134 \n",
       "L 1269 4134 \n",
       "L 1269 2991 \n",
       "Q 1406 3038 1543 3061 \n",
       "Q 1681 3084 1819 3084 \n",
       "Q 2600 3084 3056 2656 \n",
       "Q 3513 2228 3513 1497 \n",
       "Q 3513 744 3044 326 \n",
       "Q 2575 -91 1722 -91 \n",
       "Q 1428 -91 1123 -41 \n",
       "Q 819 9 494 109 \n",
       "L 494 744 \n",
       "Q 775 591 1075 516 \n",
       "Q 1375 441 1709 441 \n",
       "Q 2250 441 2565 725 \n",
       "Q 2881 1009 2881 1497 \n",
       "Q 2881 1984 2565 2268 \n",
       "Q 2250 2553 1709 2553 \n",
       "Q 1456 2553 1204 2497 \n",
       "Q 953 2441 691 2322 \n",
       "L 691 4666 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-32\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_3\">\n",
       "     <g id=\"line2d_5\">\n",
       "      <path d=\"M 140.438619 273.312 \n",
       "L 140.438619 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_6\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"140.438619\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_3\">\n",
       "      <!-- 5000 -->\n",
       "      <g transform=\"translate(127.713619 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-35\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_4\">\n",
       "     <g id=\"line2d_7\">\n",
       "      <path d=\"M 187.490002 273.312 \n",
       "L 187.490002 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_8\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"187.490002\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_4\">\n",
       "      <!-- 7500 -->\n",
       "      <g transform=\"translate(174.765002 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-37\" d=\"M 525 4666 \n",
       "L 3525 4666 \n",
       "L 3525 4397 \n",
       "L 1831 0 \n",
       "L 1172 0 \n",
       "L 2766 4134 \n",
       "L 525 4134 \n",
       "L 525 4666 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-37\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_5\">\n",
       "     <g id=\"line2d_9\">\n",
       "      <path d=\"M 234.541386 273.312 \n",
       "L 234.541386 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_10\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"234.541386\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_5\">\n",
       "      <!-- 10000 -->\n",
       "      <g transform=\"translate(218.635136 287.910437) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-31\" d=\"M 794 531 \n",
       "L 1825 531 \n",
       "L 1825 4091 \n",
       "L 703 3866 \n",
       "L 703 4441 \n",
       "L 1819 4666 \n",
       "L 2450 4666 \n",
       "L 2450 531 \n",
       "L 3481 531 \n",
       "L 3481 0 \n",
       "L 794 0 \n",
       "L 794 531 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_6\">\n",
       "     <g id=\"line2d_11\">\n",
       "      <path d=\"M 281.592769 273.312 \n",
       "L 281.592769 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_12\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"281.592769\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_6\">\n",
       "      <!-- 12500 -->\n",
       "      <g transform=\"translate(265.686519 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-32\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_7\">\n",
       "     <g id=\"line2d_13\">\n",
       "      <path d=\"M 328.644153 273.312 \n",
       "L 328.644153 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_14\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"328.644153\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_7\">\n",
       "      <!-- 15000 -->\n",
       "      <g transform=\"translate(312.737903 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"xtick_8\">\n",
       "     <g id=\"line2d_15\">\n",
       "      <path d=\"M 375.695536 273.312 \n",
       "L 375.695536 7.2 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_16\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#m2c47ecf537\" x=\"375.695536\" y=\"273.312\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_8\">\n",
       "      <!-- 17500 -->\n",
       "      <g transform=\"translate(359.789286 287.910437) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-37\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"127.246094\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"190.869141\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"254.492188\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"matplotlib.axis_2\">\n",
       "    <g id=\"ytick_1\">\n",
       "     <g id=\"line2d_17\">\n",
       "      <path d=\"M 30.103125 254.251471 \n",
       "L 387.223125 254.251471 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_18\">\n",
       "      <defs>\n",
       "       <path id=\"me7577b5f4e\" d=\"M 0 0 \n",
       "L -3.5 0 \n",
       "\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </defs>\n",
       "      <g>\n",
       "       <use xlink:href=\"#me7577b5f4e\" x=\"30.103125\" y=\"254.251471\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_9\">\n",
       "      <!-- 1.0 -->\n",
       "      <g transform=\"translate(7.2 258.05069) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-2e\" d=\"M 684 794 \n",
       "L 1344 794 \n",
       "L 1344 0 \n",
       "L 684 0 \n",
       "L 684 794 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_2\">\n",
       "     <g id=\"line2d_19\">\n",
       "      <path d=\"M 30.103125 217.157951 \n",
       "L 387.223125 217.157951 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_20\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#me7577b5f4e\" x=\"30.103125\" y=\"217.157951\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_10\">\n",
       "      <!-- 1.5 -->\n",
       "      <g transform=\"translate(7.2 220.95717) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-31\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_3\">\n",
       "     <g id=\"line2d_21\">\n",
       "      <path d=\"M 30.103125 180.064431 \n",
       "L 387.223125 180.064431 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_22\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#me7577b5f4e\" x=\"30.103125\" y=\"180.064431\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_11\">\n",
       "      <!-- 2.0 -->\n",
       "      <g transform=\"translate(7.2 183.86365) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-32\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_4\">\n",
       "     <g id=\"line2d_23\">\n",
       "      <path d=\"M 30.103125 142.970911 \n",
       "L 387.223125 142.970911 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_24\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#me7577b5f4e\" x=\"30.103125\" y=\"142.970911\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_12\">\n",
       "      <!-- 2.5 -->\n",
       "      <g transform=\"translate(7.2 146.77013) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-32\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_5\">\n",
       "     <g id=\"line2d_25\">\n",
       "      <path d=\"M 30.103125 105.877391 \n",
       "L 387.223125 105.877391 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_26\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#me7577b5f4e\" x=\"30.103125\" y=\"105.877391\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_13\">\n",
       "      <!-- 3.0 -->\n",
       "      <g transform=\"translate(7.2 109.67661) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-33\" d=\"M 2597 2516 \n",
       "Q 3050 2419 3304 2112 \n",
       "Q 3559 1806 3559 1356 \n",
       "Q 3559 666 3084 287 \n",
       "Q 2609 -91 1734 -91 \n",
       "Q 1441 -91 1130 -33 \n",
       "Q 819 25 488 141 \n",
       "L 488 750 \n",
       "Q 750 597 1062 519 \n",
       "Q 1375 441 1716 441 \n",
       "Q 2309 441 2620 675 \n",
       "Q 2931 909 2931 1356 \n",
       "Q 2931 1769 2642 2001 \n",
       "Q 2353 2234 1838 2234 \n",
       "L 1294 2234 \n",
       "L 1294 2753 \n",
       "L 1863 2753 \n",
       "Q 2328 2753 2575 2939 \n",
       "Q 2822 3125 2822 3475 \n",
       "Q 2822 3834 2567 4026 \n",
       "Q 2313 4219 1838 4219 \n",
       "Q 1578 4219 1281 4162 \n",
       "Q 984 4106 628 3988 \n",
       "L 628 4550 \n",
       "Q 988 4650 1302 4700 \n",
       "Q 1616 4750 1894 4750 \n",
       "Q 2613 4750 3031 4423 \n",
       "Q 3450 4097 3450 3541 \n",
       "Q 3450 3153 3228 2886 \n",
       "Q 3006 2619 2597 2516 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-33\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_6\">\n",
       "     <g id=\"line2d_27\">\n",
       "      <path d=\"M 30.103125 68.783871 \n",
       "L 387.223125 68.783871 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_28\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#me7577b5f4e\" x=\"30.103125\" y=\"68.783871\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_14\">\n",
       "      <!-- 3.5 -->\n",
       "      <g transform=\"translate(7.2 72.58309) scale(0.1 -0.1)\">\n",
       "       <use xlink:href=\"#DejaVuSans-33\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-35\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "    <g id=\"ytick_7\">\n",
       "     <g id=\"line2d_29\">\n",
       "      <path d=\"M 30.103125 31.690351 \n",
       "L 387.223125 31.690351 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #b0b0b0; stroke-width: 0.8; stroke-linecap: square\"/>\n",
       "     </g>\n",
       "     <g id=\"line2d_30\">\n",
       "      <g>\n",
       "       <use xlink:href=\"#me7577b5f4e\" x=\"30.103125\" y=\"31.690351\" style=\"stroke: #000000; stroke-width: 0.8\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "     <g id=\"text_15\">\n",
       "      <!-- 4.0 -->\n",
       "      <g transform=\"translate(7.2 35.48957) scale(0.1 -0.1)\">\n",
       "       <defs>\n",
       "        <path id=\"DejaVuSans-34\" d=\"M 2419 4116 \n",
       "L 825 1625 \n",
       "L 2419 1625 \n",
       "L 2419 4116 \n",
       "z\n",
       "M 2253 4666 \n",
       "L 3047 4666 \n",
       "L 3047 1625 \n",
       "L 3713 1625 \n",
       "L 3713 1100 \n",
       "L 3047 1100 \n",
       "L 3047 0 \n",
       "L 2419 0 \n",
       "L 2419 1100 \n",
       "L 313 1100 \n",
       "L 313 1709 \n",
       "L 2253 4666 \n",
       "z\n",
       "\" transform=\"scale(0.015625)\"/>\n",
       "       </defs>\n",
       "       <use xlink:href=\"#DejaVuSans-34\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-2e\" x=\"63.623047\"/>\n",
       "       <use xlink:href=\"#DejaVuSans-30\" x=\"95.410156\"/>\n",
       "      </g>\n",
       "     </g>\n",
       "    </g>\n",
       "   </g>\n",
       "   <g id=\"line2d_31\">\n",
       "    <path d=\"M 46.335852 19.296 \n",
       "L 47.27688 174.387854 \n",
       "L 48.217908 190.71868 \n",
       "L 49.158935 196.555153 \n",
       "L 50.099963 201.577653 \n",
       "L 51.040991 205.775514 \n",
       "L 51.982018 211.624563 \n",
       "L 52.923046 213.659129 \n",
       "L 53.864074 216.447495 \n",
       "L 54.805101 217.801124 \n",
       "L 55.746129 215.732139 \n",
       "L 56.687157 220.601756 \n",
       "L 57.628184 222.392817 \n",
       "L 58.569212 218.351287 \n",
       "L 59.51024 223.920377 \n",
       "L 60.451267 224.407113 \n",
       "L 61.392295 221.383264 \n",
       "L 62.333323 226.64536 \n",
       "L 63.27435 227.663748 \n",
       "L 64.215378 226.594632 \n",
       "L 65.156406 226.68268 \n",
       "L 66.097433 227.185494 \n",
       "L 67.038461 226.696132 \n",
       "L 67.979489 228.438994 \n",
       "L 68.920516 229.761122 \n",
       "L 69.861544 230.748991 \n",
       "L 70.802572 228.368394 \n",
       "L 72.684627 234.551216 \n",
       "L 73.625655 231.512784 \n",
       "L 74.566682 230.832874 \n",
       "L 75.50771 230.561193 \n",
       "L 76.448738 234.734946 \n",
       "L 77.389765 230.576493 \n",
       "L 78.330793 228.988688 \n",
       "L 79.271821 233.106186 \n",
       "L 80.212848 235.127336 \n",
       "L 81.153876 234.159808 \n",
       "L 83.035931 237.99159 \n",
       "L 83.976959 235.123507 \n",
       "L 84.917987 236.44269 \n",
       "L 85.859014 237.538594 \n",
       "L 86.800042 236.950739 \n",
       "L 87.74107 236.619194 \n",
       "L 88.682097 241.560278 \n",
       "L 89.623125 238.506272 \n",
       "L 90.564153 240.847726 \n",
       "L 91.50518 234.652849 \n",
       "L 92.446208 238.934408 \n",
       "L 93.387236 238.152441 \n",
       "L 94.328263 237.597263 \n",
       "L 95.269291 239.947499 \n",
       "L 96.210319 239.091491 \n",
       "L 97.151346 242.736952 \n",
       "L 98.092374 239.518204 \n",
       "L 99.033402 242.98365 \n",
       "L 99.974429 245.38403 \n",
       "L 100.915457 239.560858 \n",
       "L 101.856485 244.385646 \n",
       "L 102.797512 238.979299 \n",
       "L 103.73854 239.281465 \n",
       "L 104.679568 238.837931 \n",
       "L 105.620595 241.911085 \n",
       "L 106.561623 242.141138 \n",
       "L 107.502651 243.102749 \n",
       "L 108.443678 244.980196 \n",
       "L 109.384706 245.468293 \n",
       "L 110.325734 244.755944 \n",
       "L 111.266761 238.95818 \n",
       "L 112.207789 243.567455 \n",
       "L 113.148817 242.276218 \n",
       "L 114.089844 243.448426 \n",
       "L 115.030872 247.24692 \n",
       "L 115.9719 243.716225 \n",
       "L 116.912927 245.411888 \n",
       "L 117.853955 246.557662 \n",
       "L 118.794983 246.249111 \n",
       "L 119.73601 247.829212 \n",
       "L 120.677038 241.175388 \n",
       "L 121.618066 250.878142 \n",
       "L 122.559093 249.373293 \n",
       "L 123.500121 244.832372 \n",
       "L 124.441149 245.409491 \n",
       "L 125.382176 249.304479 \n",
       "L 126.323204 248.342161 \n",
       "L 127.264232 245.760067 \n",
       "L 128.205259 251.745461 \n",
       "L 129.146287 248.361431 \n",
       "L 130.087315 248.912912 \n",
       "L 131.028342 251.736998 \n",
       "L 132.910398 248.52146 \n",
       "L 133.851425 247.624549 \n",
       "L 134.792453 251.948824 \n",
       "L 135.733481 250.797726 \n",
       "L 136.674508 250.774246 \n",
       "L 137.615536 251.54377 \n",
       "L 138.556564 250.195438 \n",
       "L 139.497591 249.399435 \n",
       "L 140.438619 250.88619 \n",
       "L 141.379647 255.084741 \n",
       "L 142.320674 251.616342 \n",
       "L 143.261702 249.651925 \n",
       "L 144.20273 251.403905 \n",
       "L 145.143757 252.835015 \n",
       "L 146.084785 248.819681 \n",
       "L 147.025813 250.619073 \n",
       "L 147.96684 255.223001 \n",
       "L 148.907868 249.575108 \n",
       "L 149.848896 250.932257 \n",
       "L 150.789923 255.384612 \n",
       "L 151.730951 255.116553 \n",
       "L 152.671979 252.256667 \n",
       "L 153.613006 250.966872 \n",
       "L 154.554034 251.659491 \n",
       "L 155.495062 251.316414 \n",
       "L 156.436089 251.852276 \n",
       "L 157.377117 255.054717 \n",
       "L 158.318145 253.944786 \n",
       "L 159.259172 251.47868 \n",
       "L 160.2002 254.847958 \n",
       "L 161.141228 254.455639 \n",
       "L 162.082255 253.52621 \n",
       "L 163.023283 251.586733 \n",
       "L 163.964311 257.112851 \n",
       "L 164.905338 253.547497 \n",
       "L 165.846366 254.15258 \n",
       "L 166.787394 249.688609 \n",
       "L 167.728421 253.867527 \n",
       "L 168.669449 253.640905 \n",
       "L 169.610477 253.946608 \n",
       "L 170.551504 254.948742 \n",
       "L 172.43356 253.350502 \n",
       "L 173.374587 257.424639 \n",
       "L 174.315615 257.297337 \n",
       "L 175.256643 256.166279 \n",
       "L 176.19767 255.299663 \n",
       "L 177.138698 256.002342 \n",
       "L 178.079726 256.035908 \n",
       "L 179.020753 254.01169 \n",
       "L 179.961781 257.505223 \n",
       "L 180.902809 256.580977 \n",
       "L 181.843836 255.844652 \n",
       "L 182.784864 252.936781 \n",
       "L 183.725892 255.779058 \n",
       "L 184.666919 255.209315 \n",
       "L 185.607947 253.401937 \n",
       "L 186.548975 258.68957 \n",
       "L 187.490002 257.472899 \n",
       "L 188.43103 255.959347 \n",
       "L 189.372058 253.619981 \n",
       "L 190.313085 256.595848 \n",
       "L 191.254113 255.120426 \n",
       "L 192.195141 256.039048 \n",
       "L 193.136168 259.868495 \n",
       "L 194.077196 257.780672 \n",
       "L 195.018224 253.630266 \n",
       "L 195.959251 253.619123 \n",
       "L 196.900279 256.286364 \n",
       "L 197.841307 257.740344 \n",
       "L 198.782334 257.614024 \n",
       "L 199.723362 258.75198 \n",
       "L 200.66439 257.143698 \n",
       "L 202.546445 254.673572 \n",
       "L 203.487473 257.285822 \n",
       "L 204.4285 254.770318 \n",
       "L 205.369528 254.33581 \n",
       "L 206.310556 260.035426 \n",
       "L 207.251583 257.413199 \n",
       "L 208.192611 256.756177 \n",
       "L 209.133639 261.216 \n",
       "L 210.074667 256.104094 \n",
       "L 211.015694 257.735162 \n",
       "L 211.956722 255.845824 \n",
       "L 212.89775 257.815061 \n",
       "L 213.838777 256.76017 \n",
       "L 214.779805 257.761812 \n",
       "L 215.720833 257.902849 \n",
       "L 216.66186 256.541322 \n",
       "L 217.602888 257.396347 \n",
       "L 218.543916 255.101584 \n",
       "L 219.484943 255.479157 \n",
       "L 220.425971 256.138951 \n",
       "L 221.366999 254.417761 \n",
       "L 222.308026 258.205691 \n",
       "L 223.249054 256.939562 \n",
       "L 224.190082 253.727672 \n",
       "L 225.131109 255.208603 \n",
       "L 226.072137 257.764041 \n",
       "L 227.013165 254.181225 \n",
       "L 228.89522 257.188687 \n",
       "L 229.836248 256.699134 \n",
       "L 230.777275 253.690979 \n",
       "L 231.718303 254.66104 \n",
       "L 232.659331 257.533753 \n",
       "L 233.600358 256.502449 \n",
       "L 234.541386 253.467125 \n",
       "L 235.482414 258.163754 \n",
       "L 236.423441 257.207957 \n",
       "L 237.364469 254.811544 \n",
       "L 238.305497 253.708277 \n",
       "L 239.246524 256.935874 \n",
       "L 240.187552 256.091646 \n",
       "L 241.12858 254.467105 \n",
       "L 242.069607 257.27077 \n",
       "L 243.010635 254.548092 \n",
       "L 243.951663 255.057564 \n",
       "L 244.89269 254.090674 \n",
       "L 245.833718 256.560168 \n",
       "L 246.774746 255.41117 \n",
       "L 247.715773 252.411513 \n",
       "L 248.656801 259.78546 \n",
       "L 249.597829 254.464275 \n",
       "L 250.538856 254.618984 \n",
       "L 251.479884 259.250142 \n",
       "L 252.420912 255.082884 \n",
       "L 253.361939 253.566432 \n",
       "L 254.302967 253.551017 \n",
       "L 255.243995 256.075006 \n",
       "L 256.185022 252.007458 \n",
       "L 257.12605 251.480944 \n",
       "L 258.067078 255.988952 \n",
       "L 259.008105 253.249497 \n",
       "L 259.949133 253.861469 \n",
       "L 260.890161 252.020034 \n",
       "L 261.831188 253.760615 \n",
       "L 262.772216 253.114046 \n",
       "L 263.713244 254.557289 \n",
       "L 264.654271 254.085518 \n",
       "L 265.595299 252.737097 \n",
       "L 266.536327 252.501118 \n",
       "L 267.477354 252.056002 \n",
       "L 268.418382 253.98752 \n",
       "L 269.35941 253.483742 \n",
       "L 270.300437 253.794575 \n",
       "L 271.241465 253.447005 \n",
       "L 273.12352 253.616072 \n",
       "L 274.064548 251.173233 \n",
       "L 275.005576 254.100013 \n",
       "L 275.946603 252.765459 \n",
       "L 276.887631 250.381741 \n",
       "L 277.828659 253.930468 \n",
       "L 278.769686 250.909573 \n",
       "L 279.710714 252.017717 \n",
       "L 280.651742 252.395338 \n",
       "L 281.592769 254.340104 \n",
       "L 282.533797 251.177319 \n",
       "L 283.474825 250.849223 \n",
       "L 284.415852 255.382865 \n",
       "L 285.35688 255.42792 \n",
       "L 286.297908 253.928204 \n",
       "L 287.238935 248.33666 \n",
       "L 288.179963 251.858564 \n",
       "L 289.120991 249.805471 \n",
       "L 290.062018 251.47233 \n",
       "L 291.944074 250.534508 \n",
       "L 292.885101 251.032298 \n",
       "L 293.826129 252.154796 \n",
       "L 294.767157 251.145508 \n",
       "L 295.708184 251.673269 \n",
       "L 296.649212 249.05497 \n",
       "L 297.59024 250.783912 \n",
       "L 299.472295 250.434945 \n",
       "L 300.413323 251.777874 \n",
       "L 301.35435 249.578106 \n",
       "L 302.295378 250.713533 \n",
       "L 303.236406 247.110513 \n",
       "L 304.177433 251.18519 \n",
       "L 305.118461 250.592939 \n",
       "L 306.059489 249.285439 \n",
       "L 307.000516 251.02961 \n",
       "L 307.941544 248.630397 \n",
       "L 308.882572 248.566244 \n",
       "L 309.823599 247.643546 \n",
       "L 310.764627 250.085244 \n",
       "L 311.705655 250.063506 \n",
       "L 312.646682 245.797424 \n",
       "L 313.58771 251.037905 \n",
       "L 314.528738 247.401969 \n",
       "L 315.469765 245.150651 \n",
       "L 316.410793 249.181365 \n",
       "L 317.351821 247.076111 \n",
       "L 318.292848 248.076343 \n",
       "L 319.233876 248.026721 \n",
       "L 320.174904 249.254309 \n",
       "L 321.115931 247.834678 \n",
       "L 322.997987 245.55819 \n",
       "L 323.939014 247.421125 \n",
       "L 324.880042 245.113799 \n",
       "L 325.82107 245.132451 \n",
       "L 326.762097 247.110796 \n",
       "L 327.703125 246.763934 \n",
       "L 328.644153 248.508556 \n",
       "L 329.58518 248.361529 \n",
       "L 330.526208 247.827983 \n",
       "L 331.467236 244.513651 \n",
       "L 332.408263 244.412549 \n",
       "L 333.349291 245.501608 \n",
       "L 334.290319 243.719214 \n",
       "L 335.231346 246.311982 \n",
       "L 336.172374 247.242914 \n",
       "L 337.113402 246.230477 \n",
       "L 338.054429 245.828739 \n",
       "L 339.936485 245.973919 \n",
       "L 340.877512 245.982612 \n",
       "L 341.81854 243.749981 \n",
       "L 342.759568 246.117409 \n",
       "L 343.700595 244.582358 \n",
       "L 344.641623 245.482956 \n",
       "L 345.582651 242.313282 \n",
       "L 346.523678 243.633756 \n",
       "L 347.464706 242.42803 \n",
       "L 348.405734 242.810073 \n",
       "L 349.346761 243.068895 \n",
       "L 350.287789 245.345312 \n",
       "L 351.228817 243.235866 \n",
       "L 352.169844 244.170415 \n",
       "L 353.110872 243.405401 \n",
       "L 354.0519 240.985308 \n",
       "L 354.992927 243.962842 \n",
       "L 355.933955 245.108378 \n",
       "L 356.874983 240.167966 \n",
       "L 357.81601 241.415788 \n",
       "L 358.757038 239.245524 \n",
       "L 359.698066 241.916037 \n",
       "L 360.639093 242.288024 \n",
       "L 361.580121 244.173793 \n",
       "L 362.521149 240.946688 \n",
       "L 364.403204 242.600289 \n",
       "L 365.344232 242.738252 \n",
       "L 366.285259 242.035835 \n",
       "L 367.226287 242.160072 \n",
       "L 368.167315 240.389989 \n",
       "L 369.108342 241.549303 \n",
       "L 370.04937 237.876665 \n",
       "L 370.990398 238.492228 \n",
       "L 370.990398 238.492228 \n",
       "\" clip-path=\"url(#p64b330da58)\" style=\"fill: none; stroke: #1f77b4; stroke-width: 1.5; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_3\">\n",
       "    <path d=\"M 30.103125 273.312 \n",
       "L 30.103125 7.2 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_4\">\n",
       "    <path d=\"M 387.223125 273.312 \n",
       "L 387.223125 7.2 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_5\">\n",
       "    <path d=\"M 30.103125 273.312 \n",
       "L 387.223125 273.312 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "   <g id=\"patch_6\">\n",
       "    <path d=\"M 30.103125 7.2 \n",
       "L 387.223125 7.2 \n",
       "\" style=\"fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square\"/>\n",
       "   </g>\n",
       "  </g>\n",
       " </g>\n",
       " <defs>\n",
       "  <clipPath id=\"p64b330da58\">\n",
       "   <rect x=\"30.103125\" y=\"7.2\" width=\"357.12\" height=\"266.112\"/>\n",
       "  </clipPath>\n",
       " </defs>\n",
       "</svg>\n"
      ],
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot([i[\"step\"] for i in record[\"train\"][::50]], [i[\"loss\"] for i in record[\"train\"][::50]], label=\"train\")\n",
    "plt.grid()\n",
    "plt.show()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 推理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0.4750, 0.5250])\n"
     ]
    }
   ],
   "source": [
    "#\n",
    "my_tensor = torch.tensor([0.2,0.3])\n",
    "\n",
    "probs1 = F.softmax(my_tensor, dim=-1)\n",
    "print(probs1)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T08:06:50.669884500Z",
     "start_time": "2024-05-02T08:06:50.644888300Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "概率分布: tensor([0.1000, 0.4500, 0.3500, 0.1000])\n",
      "抽取的样本索引: tensor([1])\n",
      "每个样本对应的概率: tensor([0.4500])\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "# 创建一个概率分布，表示每个类别被选中的概率\n",
    "# 这里我们有一个简单的四个类别的概率分布\n",
    "prob_dist = torch.tensor([0.1, 0.45, 0.35, 0.1])\n",
    "\n",
    "# 使用 multinomial 进行抽样\n",
    "# num_samples 表示要抽取的样本数量\n",
    "num_samples = 5\n",
    "\n",
    "# 抽取样本\n",
    "samples = torch.multinomial(prob_dist, 1, replacement=True)\n",
    "\n",
    "print(\"概率分布:\", prob_dist)\n",
    "print(\"抽取的样本索引:\", samples)\n",
    "\n",
    "# 显示每个样本对应的概率\n",
    "print(\"每个样本对应的概率:\", prob_dist[samples])"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-02T08:11:15.821771500Z",
     "start_time": "2024-05-02T08:11:15.798783Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "81ee1ebbc4ce477dbf46928fc873eba8",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/1000 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "All: I must conference were early is full of soldiers:\n",
      "Therefore this be courtedy state,\n",
      "When he would have spoke, that follows that you make me burning welcome.\n",
      "\n",
      "PETRUCHIO:\n",
      "The fouler face. But then for his majesty\n",
      "To revel it is become and stocan, and that he will be therefore can bear your patience.\n",
      "\n",
      "CAMILLO:\n",
      "Sir, the great Bolingbroke, dispersed again, being the first punishment,\n",
      "Or breathes of that contented that hath not safegualing whiterately heart\n",
      "May do me swear and me.\n",
      "\n",
      "QUEEN ELIZABETH:\n",
      "But I pray you, let me have\n",
      "A drops of such a passing sounds,\n",
      "But that the rage, my lord,\n",
      "Go their wives,\n",
      "and that thou wert death:\n",
      "And streal occasion to his children from the world,\n",
      "Than the desperate greater than a soldiers to his place.\n",
      "\n",
      "CAMILLO:\n",
      "Sir, so in this crown,\n",
      "And so he do not slaughter of the twofold chamber; but the king\n",
      "Shall give me see\n",
      "these free deposed?\n",
      "\n",
      "Gardener:\n",
      "Doth the devil that fills her on the sun.\n",
      "\n",
      "DUCHESS OF YORK:\n",
      "Why, therefore take my leave.\n",
      "\n",
      "QUEEN MARGARET:\n",
      "What is "
     ]
    }
   ],
   "source": [
    "def generate_text(model, start_string, max_len=1000, temperature=1.0, stream=True):\n",
    "    input_eval = torch.Tensor([char2idx[char] for char in start_string]).to(dtype=torch.int64, device=device).reshape(1, -1) #bacth_size=1, seq_len长度是多少都可以\n",
    "    hidden = None\n",
    "    text_generated = [] #用来保存生成的文本\n",
    "    model.eval()\n",
    "    pbar = tqdm(range(max_len)) # 进度条\n",
    "    print(start_string, end=\"\")\n",
    "    # no_grad是一个上下文管理器，用于指定在其中的代码块中不需要计算梯度。在这个区域内，不会记录梯度信息，用于在生成文本时不影响模型权重。\n",
    "    with torch.no_grad():\n",
    "        for i in pbar:\n",
    "            logits, hidden = model(input_eval, hidden=hidden)\n",
    "            # 温度采样，较高的温度会增加预测结果的多样性，较低的温度则更加保守。\n",
    "            logits = logits[0, -1, :] / temperature\n",
    "            # using multinomial to sampling\n",
    "            probs = F.softmax(logits, dim=-1) #算为概率分布\n",
    "            idx = torch.multinomial(probs, 1).item() #从概率分布中抽取一个样本,取概率较大的那些\n",
    "            input_eval = torch.Tensor([idx]).to(dtype=torch.int64, device=device).reshape(1, -1) #把idx转为tensor\n",
    "            text_generated.append(idx)\n",
    "            if stream:\n",
    "                print(idx2char[idx], end=\"\", flush=True)\n",
    "    return \"\".join([idx2char[i] for i in text_generated])\n",
    "\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/text_generation/best.ckpt\", map_location=\"cpu\"))\n",
    "start_string = \"All: \"\n",
    "res = generate_text(model, start_string, max_len=1000, temperature=0.5, stream=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pytorch",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.8"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
